为什么 SQLite 官方建议把小于100kb的文件直接存进数据库?
|
admin
2026年1月18日 14:32
本文热度 21
|
传统教条:
“数据库是存结构化数据的,文件(图片、PDF、视频)要去存对象存储(AWS S3, OSS)或者硬盘文件系统。数据库里只存路径(/uploads/image.jpg)。”
现实痛点:
- 1. 事务不一致: 用户上传头像,你先保存了文件,结果数据库插入失败回滚了。现在你的磁盘上多了一个永远没人引用的“孤儿文件”。
- 2. 备份噩梦: 备份时,你既要备份数据库 SQL,又要打包文件目录。恢复时,如果这两个备份的时间点对不上,数据就错乱了。
- 3. 小文件性能差: 对于几万个 1KB 的小文件,操作系统的文件系统(Ext4/NTFS)在遍历和读取时的 inode 开销其实非常大。
BLOB 的逆袭:
SQLite 官方测试表明:对于小于 100KB 的文件,直接读写数据库的 BLOB 字段,比读写文件系统快 35%! 因为它减少了系统调用(syscall)的次数。
1. 核心原理:BLOB 是什么?
BLOB (Binary Large Object) 是数据库中专门用来存储二进制数据(图片、音频、压缩包)的字段类型。
- • MySQL:
TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB
当你选择存 BLOB 时,文件不再是散落在磁盘上的碎片,而是数据库页(Page)的一部分。
2. BLOB 逆袭的三大理由
理由一:完美的 ACID 事务支持 (The Killer Feature)
这是 BLOB 最大的杀手锏。
- • 文件系统方案: 文件操作和数据库操作是分离的,没有原子性。
- • 结果: 要么都成功,要么都失败。永远不会出现“有记录无文件”或“有文件无记录”的数据腐烂问题。
理由二:单文件备份 (Simplified Backup)
想象一下你要迁移服务器。
- • 传统方案: 此时你需要用
rsync 同步几百万个小文件(极慢),还要导出 MySQL。 - • BLOB 方案: 你只需要
mysqldump 或者拷贝 SQLite 的那个 .db 文件。一个文件带走所有,数据一致性 100% 保证。
理由三:小文件读写性能
现代数据库(如 PostgreSQL 和 SQLite)对变长数据做了深度优化。当文件很小(例如 < 20KB)时,它们通常直接存储在 B+ 树的叶子节点中。读取这行数据时,文件内容已经被加载到 DB Buffer Pool(内存)里了,无需二次 I/O。
3. 实战场景:哪些情况 必须 用 BLOB?
注意,我们不是建议你把 4K 电影存进去。BLOB 适用于 “小、重要、强关联” 的数据。
场景一:用户头像与缩略图 (Small Images)
- • 特征: 文件极小(通常 < 50KB),数量极大。
- • 优势: 使用 BLOB 存储,Web Server 在查询用户 Profile 时,一次 SQL 就能把“昵称”和“头像数据”一起查出来,直接转 Base64 返回给前端,减少了一次 HTTP 请求或文件 IO。
场景二:关键业务凭证 (Sensitive Contracts)
- • 特征: 电子合同 PDF、支付签名证据、医疗检查报告。
- • 优势: 放在文件系统里,任何有服务器登录权限的人都能
ls 看到文件。放在数据库里,文件受到数据库 ACL(访问控制列表)的保护。你可以轻松对 BLOB 字段进行加密存储,随数据库权限管理。
场景三:游戏存档与配置 (Game Saves)
- • 优势: 很多单机或手游服务端使用 SQLite/MySQL 存储玩家存档。如果更新存档时发生断电,数据库的 WAL (Write-Ahead Log) 机制能保证存档不损坏。
场景四:动态生成的报表/发票
- • 特征: 系统生成的 HTML 或 XML 快照。
- • 优势: 这些通常是“只读”且“永久归档”的。存入 BLOB 可以方便地随业务数据一起冷备。
4. 什么时候 绝对不要 用 BLOB?
虽然 BLOB 很香,但别走极端。以下情况请老老实实存文件系统或 OSS:
- 1. 大文件 (> 1MB): 数据库的 Buffer Pool 是宝贵的内存资源。如果你读取一个 500MB 的视频 BLOB,它会瞬间把热点数据的缓存挤出内存,导致数据库整体抖动。
- 2. 流式访问 (Streaming): 数据库一般不支持像文件系统那样的
seek() 操作(从第 100MB 开始读)。 - 3. CDN 分发: 如果你的图片需要通过 CDN 全球加速,存 OSS 是最佳选择,因为 OSS 原生对接 CDN。存数据库还得自己写个 API 把 BLOB 吐出来,多了一层性能瓶颈。
5. 最佳实践总结
如果你决定尝试 BLOB 方案,请遵循以下原则:
- 1. 分离存储表: 不要把 BLOB 字段和经常查询的业务字段(如
username, age)放在同一张表!
- • 差评:
users (id, name, avatar_blob) -> 查 name 时会拖慢速度。 - • 好评:
users (id, name) + user_avatars (user_id, avatar_blob)。
- 2. 设置大小限制: 在应用层严格限制上传文件大小(例如 max 256KB)。
- • PostgreSQL:
TOAST 机制处理大字段非常优秀。 - • MySQL: 性能稍弱,注意
max_allowed_packet 配置。
阅读原文:原文链接
该文章在 2026/1/19 10:54:21 编辑过