V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
liyafe1997
V2EX  ›  数据库

用 PostgreSQL 存图片等 binary 有什么坑吗

  •  
  •   liyafe1997 · 4 小时 28 分钟前 · 1704 次点击

    如题,大概每个主条目下面关联有几张到一两百张不等的图片/文档之类的附件,每张图最大 500KB (入库时超大会自动压缩),文档也是不超过 500KB 。

    目前测试数据(几十/百来个主条目)跑起来感觉挺香的,也没见什么性能问题。特别是设置好外键和 cascade delete 之后,主条目删除会自动把存 binary 的表中关联的附件一并干掉,比放文件系统好维护。文件系统还要自己处理数据关联和清理逻辑。

    就是不知道以后数据量大了会有什么坑,预计之后主条目有数万个这样的量级。

    43 条回复    2025-09-23 20:01:26 +08:00
    KongLiu
        1
    KongLiu  
       4 小时 21 分钟前
    数据库占用 IO 太高了,高并发就废了,而且以后配合 CDN 做加速也不方便,还有数据库存储一般都比对象云存储贵把
    wangtian2020
        2
    wangtian2020  
       4 小时 10 分钟前
    我 sqlite 都不敢这么存
    liyafe1997
        3
    liyafe1997  
    OP
       4 小时 7 分钟前
    @KongLiu 没有什么太高的并发需求,正常用户应该没考虑到高并发这个量级,但是怕的是 Internet 上乱跑的爬虫/搜索引擎 Bot 之类的。
    「以后配合 CDN 做加速也不方便」,这个为什么呢?我还想着以后用 CDN 来帮缓存一些图,不用每次都进我的后端/数据库 IO 。
    zhengfan2016
        4
    zhengfan2016  
       3 小时 50 分钟前   ❤️ 2
    后面接手项目的开发:安卓架构(bushi
    JYii
        5
    JYii  
       3 小时 48 分钟前
    @liyafe1997 #3 你自己都说出隐患了,一个查询 api 就能把你 DB 打死。
    Vegetable
        6
    Vegetable  
       3 小时 43 分钟前
    IO 很难受,这么弄也很难做到正常文件服务器的能力,本来如空气一般自然的功能你都得自己实现,比如 http 304 。
    你如果一开始选了这个架构,后边会越来越难受,只有一开始能爽点,与其后边难受,不如一开始做好资源管理,把删除的逻辑弄好。
    KongLiu
        7
    KongLiu  
       3 小时 41 分钟前
    @liyafe1997 用 OSS 配置一下就好了,你这种方式全靠自己控制。搞不到 OSS 配置本身就提供的功能,你自己要写一大堆
    liyafe1997
        8
    liyafe1997  
    OP
       3 小时 41 分钟前
    @JYii 感觉在 HTTP Server 或者套一层 sqiud 做缓存能解决?甚至最外面还有一层 CDN 也能缓存?总之就是不用每次 HTTP GET 都去查 DB 。
    liyafe1997
        9
    liyafe1997  
    OP
       3 小时 40 分钟前
    @KongLiu 那还得装一套 OSS
    xtreme1
        10
    xtreme1  
       3 小时 38 分钟前
    "条目"具体是什么东西?
    zephyru
        11
    zephyru  
       3 小时 36 分钟前
    CDN 一般不都是通过图片的文件路径地址去访问的?
    存文件系统里直接上传对应文件保持路径,项目里替换下请求的地址就好了。
    你这种模式也并不是不能用 CDN 但确实不方便。
    小文件存数据库主要问题还是开销大吧,基本没见过正经系统把文件直接存数据库里的。
    liyafe1997
        12
    liyafe1997  
    OP
       3 小时 36 分钟前
    @xtreme1 你就理解成类似 V2EX 的帖子就好了,一条帖子下面可能挂有很多图片甚至文档等附件。
    AutumnVerse
        13
    AutumnVerse  
       3 小时 35 分钟前 via iPhone
    以前自己玩具项目这样搞过

    就像楼上说的,数据库 io 扛不住,而且没法优化
    liyafe1997
        14
    liyafe1997  
    OP
       3 小时 34 分钟前
    @zephyru CDN 请求我的 Server 也是 HTTP GET 哇,我的后端访问数据库中的图片也是 HTTP GET ( RESTful API ),查 db 再把图 binary data 通过 http response 弹回给你
    liyafe1997
        15
    liyafe1997  
    OP
       3 小时 33 分钟前
    @AutumnVerse 现在想到的解决方案是在 HTTP Server 上做缓存,不知道加上这个之后,还有什么坑
    AutumnVerse
        16
    AutumnVerse  
       3 小时 33 分钟前 via iPhone
    正经做法是数据库存 oos 地址,后端返回 oos 地址,前端直接请求 oos ,这样减少服务端 io
    AutumnVerse
        17
    AutumnVerse  
       3 小时 32 分钟前 via iPhone
    @liyafe1997 缓存里面放图片?那你缓存的多大啊,你不怕缓存被撑爆吗
    liyafe1997
        18
    liyafe1997  
    OP
       3 小时 32 分钟前
    @AutumnVerse 不想(懒得)再引入一套 OSS 了🤣
    AutumnVerse
        19
    AutumnVerse  
       3 小时 29 分钟前 via iPhone
    直接放磁盘路径都比放数据库好,直接放磁盘有一些文件系统,操作系统相关的优化方案,而且可以挂载远程磁盘的方式做分布式
    liyafe1997
        20
    liyafe1997  
    OP
       3 小时 28 分钟前
    @AutumnVerse 直接放磁盘的话...我还是考虑 OSS 吧🤣
    感谢解答
    zephyru
        21
    zephyru  
       3 小时 27 分钟前
    @liyafe1997
    一般来说,大家说图片 CDN 可能是 OSS 那种模式的。
    所有的流量全部走 CDN 不会再打到服务器上。
    你这种情况,可能只适合使用套在域名上那种作为前置缓存的 CDN (缓存规则,失效诸如此类的先另说)。
    你想使用传统使用 CDN 的方式,得先从 DB 里下载出来再上传,这就是麻烦的点。
    这么看来主要的坑点,除了开销大,就是传统的方案需要你自己再另外实现。
    xtreme1
        22
    xtreme1  
       3 小时 26 分钟前
    额, 就是富文本吗. 现在方案都很成熟了啊, 文本存 pg, 附件上 oss, 索引上 es.
    KongLiu
        23
    KongLiu  
       3 小时 25 分钟前
    @liyafe1997 能用和好用是两码事,你这个只能算是能用水平,远远谈不上好用。OSS 配合 CDN 能很容易的改变缓存策略,你这个每一点改动都要改代码。除非你这个项目是玩具项目做出来不用考虑维护的,不然早晚有坑等着呢,你现在的想象中的美好都基于没几个人用的情况。
    chambered
        24
    chambered  
       3 小时 23 分钟前
    我觉得 pg 的 bytea 就是用来存这些二进制数据的,所以几十 kb 应该没什么问题,太大肯定不行。还是看文档怎么介绍的吧
    skallz
        25
    skallz  
       3 小时 9 分钟前
    之前只有富文本这么干过,当时是为了图省事把里面所有图片资源转成 base64 嵌在富文本里,但是后面也是相当难受,最后把富文本生成一个 json 文件传 oss 了
    ytmsdy
        26
    ytmsdy  
       3 小时 8 分钟前
    数据库备份的时候,你就会知道这是一个噩梦,备份文件动不动就是上百 G 。
    另外数据还原也是一个问题,很慢,很烦。
    我们之前把身份证照片转成了 base64 ,存到了数据库里,然后自动备份服务器的空间动不动就满了。贼烦
    donaldturinglee
        27
    donaldturinglee  
       3 小时 7 分钟前
    正经做法还是上 OSS
    SoviaPhilo
        28
    SoviaPhilo  
       3 小时 6 分钟前
    除非硬件资源限制了, 最好是能分离, 毕竟如楼上说的方案很成熟了。
    而方案成熟那是无数前人拿血和泪换来的。

    另外, 数据量大了, 你现在的设计绝大多数都会是坑, 不止是图片。毕竟大数据量和小数据量在设计上肯定是不一样的
    kenilalexandra
        29
    kenilalexandra  
       3 小时 4 分钟前
    OSS 的出现就是为了解决你不知道的“有什么坑吗”的
    geminikingfall
        30
    geminikingfall  
       2 小时 55 分钟前
    这是个什么操作?这不上块存储吗?
    billbob
        31
    billbob  
       2 小时 43 分钟前
    上 OSS
    liyafe1997
        32
    liyafe1997  
    OP
       2 小时 38 分钟前
    @ytmsdy base64 那会增大很多吧,正确不应该用 bytea?
    jjx
        33
    jjx  
       2 小时 20 分钟前
    500k 就是 5m 带宽了

    两个人并发就带宽报警了

    这种还是用 7 牛云之类的吧
    june4
        34
    june4  
       1 小时 50 分钟前
    楼上都没给出实锤证据啊,说明可行?
    存成文件也是要 IO 的,且存数据库前面也可以配缓存,不管是文件缓存还是 CDN 缓存

    可能就是备份比文件方式不方便一点,如果图片量是巨大的话。
    sagnitude
        35
    sagnitude  
       1 小时 42 分钟前
    没什么太大问题,不要被吓到了。
    平时这种应用场景很少,所以大家没做过,可能第一反应就是反对。
    我就举一个例子,GIS 地图服务器,比如卫星图的图片,一般都是存数据库里的,几十 TB 照样存,我见过的,sqlite ,postgresql ,mongodb ,都有。比如 postgresql 直接就有一个 PostGIS 扩展来做这个。
    全国地图总数据量应该是 10 亿图片量级,存数据库也没问题。
    才几万个根本无所谓的。

    而且 sqlite 也可以的,关键是做好分库分表,我自己就做过 sqlite 地图服务,每个 sqlite 数据库最多存储大概 1-2GB 的数据,没什么问题。

    为什么不用 OSS 或者文件系统?因为他扛不住哈哈哈,我一次性导 20 亿文件进去,OSS 要几个月,文件系统也要等一个月,RAID 也没什么用,存储最佳方式就是数据库,可以解决小文件碎片化的问题。
    irrigate2554
        36
    irrigate2554  
       1 小时 32 分钟前
    规模小的话应该没啥问题,memos 就支持存储附件到数据库,我也是这么用的。就怕规模越来越大,加上动不动 select * , 这样总有一天要炸。
    irrigate2554
        37
    irrigate2554  
       1 小时 28 分钟前
    有一个明显的劣势就是存视频的话流式播放功能就无法实现了。
    CEBBCAT
        38
    CEBBCAT  
       1 小时 21 分钟前
    @sagnitude #35 请教下,是这个逻辑吗:OSS 是网络 IO(耗时),FS 是系统调用,SQLite 跑在用户空间,众所周知有时候可以比硬盘快
    sagnitude
        39
    sagnitude  
       1 小时 4 分钟前
    @CEBBCAT
    1. OSS 每一个操作都是网络,overhead 超级大,每个 stat 或者 mv cp 耗时增加哪怕 1 毫秒,乘以 20 亿的量级就是 23 天。几个月过去,项目都不要做了
    2. 数据库可以用内存加速。
    3. 文件系统对于巨量小文件的支持比较烂,碎片大,索引效率低,inode 就要占好几分之一的空间。
    对数据库来说,读写是在单个文件内部完成的,不需要文件系统操作 open() close()
    xiangyuecn
        40
    xiangyuecn  
       51 分钟前
    这么丁点数据量随便存,简单粗暴的存储架构,不要听楼上的,那些都是没卵用的提前优化

    说不定项目黄了,数据库压力都不一定有上来
    moen
        41
    moen  
       46 分钟前
    pg 有个内置扩展叫 lo ,用来存大对象
    iyaozhen
        42
    iyaozhen  
       42 分钟前
    可以这样吧,没啥问题。

    而且你又不是经常 select * ,比如帖子附件,你可以只展示名称。下载再查出内容字段

    当然 OSS 确实是标准做法
    laminux29
        43
    laminux29  
       35 分钟前
    全存数据库,最大的优势是开发与调试都极其方便,节约了程序员大量时间。就算后期性能不足,直接堆硬件也能解决。

    大部分中小项目,这么跑一点问题都没有,而且数据库天生做负载均衡与 HA 都更方便。

    当然,非常特殊的追求性能的项目,以及用户或数据量众多的大厂项目,可能没办法这么玩。
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2985 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 12:37 · PVG 20:37 · LAX 05:37 · JFK 08:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.