SQLite vs PostgreSQL / MySQL:什么时候该选 SQLite + 真实并发瓶颈在哪

· 约 5 分钟 🗄️ SQLite 在线编辑

SQLite 是世界上部署最广的数据库——每台 iOS/Android 手机里有几百个 SQLite 库,每个浏览器、每个 macOS/Windows 系统组件都在用,连 Notion / ChatGPT / Slack 桌面端都把它当本地缓存。但很多后端开发者还在把它当成”小项目玩具”,遇到真实业务就一律上 Postgres——这其实是浪费。

这篇拆解 SQLite 的真实生产能力、并发瓶颈出现在哪、什么场景该选 SQLite 而不是 Postgres / MySQL。

SQLite 的真实定位

SQLite 官方文档里有一篇 “When To Use SQLite”,明确说它的目标不是和 Postgres 竞争,而是”取代 fopen()“——做嵌入式、单机、本地存储。

适合场景

  • 嵌入式应用:桌面 / 移动 / IoT / 浏览器扩展
  • 单机 Web 服务 / CLI 工具:个人博客、文档站、内部工具
  • 读多写少的 SaaS:单租户、SaaS 阅读为主
  • 原型 / MVP:起步阶段,规模真大了再迁
  • 测试数据库:memory: 模式秒级启动

生产案例(不是玩具):

公司 / 产品SQLite 用法
iOS / Android系统通讯录 / 浏览器 / 应用本地存储
Chrome / Firefox / Safari历史记录 / 收藏夹 / 表单
Notion 桌面本地缓存 + 离线编辑
ChatGPT 桌面对话历史
Slack 桌面消息缓存
Expensify后端核心账务库(高 TPS)
PocketBase / Turso / Cloudflare D1 / fly.io LiteFS围绕 SQLite 建的现代后端栈

并发瓶颈:写 vs 读

SQLite 最常被误解的就是”它不能并发”。准确说法:读并发几乎无限,写并发严重受限

模式读并发写并发推荐
journal_mode=DELETE(默认)1(读阻塞写)1不推荐
journal_mode=WAL无限1(写者串行)生产必用

WAL(Write-Ahead Log)模式的关键特性:

  • 读不阻塞写、写不阻塞读
  • 写者仍然只能 1 个,但读者可以无数个
  • 单写者下,中等硬件 + 批量事务能跑 5000-50000 写/秒

典型并发上限

  • 写 < 100 TPS:SQLite 完全够,零调优
  • 写 100-1000 TPS:WAL + synchronous=NORMAL + 合理 PRAGMA
  • 写 1000-5000 TPS:极限区,要批量事务(一个 BEGIN…COMMIT 包多条)+ 仔细调优
  • 写 > 5000 TPS:迁 Postgres / MySQL 或分库

读 TPS:单机 SQLite 读可达 10 万-100 万 QPS(缓存命中时),瓶颈在 CPU 和磁盘 IO,不是 SQLite 本身。

SQLite vs PostgreSQL 的本质差异

维度SQLitePostgreSQL
部署进程内库,单文件独立服务,TCP 监听
并发模型写串行(1 writer)MVCC 多写者并行
类型系统动态(type affinity)强类型
默认隔离级别SERIALIZABLEREAD COMMITTED
复制 / 高可用第三方(Litestream / LiteFS / rqlite)内置流复制 + 逻辑复制
用户权限无(应用层做 RBAC)GRANT / 角色系统
存储过程不支持支持(PL/pgSQL 等)
扩展内置 FTS5 / R-Tree / JSON1PostGIS / TimescaleDB / pgvector 等
运维成本几乎为零需要 DBA / 监控

核心选择规则

  • 嵌入式 / 单机服务 / 桌面 / 移动 → SQLite
  • 多机集群 / 高并发写 / 需要复制 / 复杂权限 → Postgres / MySQL

单文件能大到多少

理论上限 281 TB(默认配置 16 TB),实际几百 GB 完全可用。

大库的注意事项

  1. VACUUM 慢——大库重建索引要小时级,用 PRAGMA auto_vacuum=INCREMENTAL + 定期 PRAGMA incremental_vacuum
  2. 必须 hot backup——.backup 命令或 VACUUM INTO,不能直接 cp
  3. WAL 文件可能很大——长事务不 commit 让 WAL 无限增长,定期 wal_checkpoint
  4. mmap_size 设大点——让 OS 自动管理缓存
  5. 索引内存占用——百万行表索引可能几 GB,cache_size 要够

详细的 PRAGMA 调优另起一篇讲。

备份:必须用 SQLite 自己的机制

最常见的错误是 cp main.db backup.db——写入过程中复制会拿到不一致的页,恢复时报 “database disk image is malformed”。

正确方法

方法用法适合
.backup 命令sqlite3 main.db ".backup backup.db"CLI 一次性热备
VACUUM INTOVACUUM INTO 'path/backup.db'输出紧凑库(3.27+)
sqlite3_backup_* API编程接口,增量复制嵌入式应用
Litestream持续把 WAL 推 S3 / B2,秒级 RPO生产 Web 服务
LiteFS文件系统层多机复制多副本部署

陷阱

  • 多进程读写时简单 cp 几乎一定坏
  • 备份完一定 PRAGMA integrity_check 验证
  • 加密库(SQLCipher)备份要带原密钥重建
  • 不要依赖 LVM / ZFS 快照——除非快照前 fsync + 加全局写锁

5 类不适合 SQLite 的场景

  1. 多机分布式集群 —— rqlite / Dqlite / LiteFS 都是绕弯,原生场景用 Postgres / TiDB
  2. 高并发写(> 5000 TPS) —— 单 writer 锁是物理瓶颈,秒杀 / 高频交易不要用
  3. 多租户 SaaS 的强权限隔离 —— SQLite 没有 GRANT,靠应用层做 RBAC,复杂场景用 Postgres
  4. 复杂存储过程 / 触发器 —— SQLite 触发器有限,没有存储过程
  5. 跨数据中心同步 —— Postgres + 物理复制更省心

灰色区

  • 大数据分析 → 用 DuckDB / ClickHouse 更快(DuckDB 详见 DuckDB vs SQLite vs Pandas
  • 时序数据 → 能用但 TimescaleDB / InfluxDB 更专
  • 图数据库 → CTE 能玩但性能差

决策清单

不确定选 SQLite 还是 Postgres 时过一遍:

  • 估算真实写 TPS(不是”在线用户数”);< 100 TPS 直接 SQLite
  • 是否需要多机?需要 → 选 Postgres 或考虑 Litestream / LiteFS
  • 是否需要数据库层权限?需要 → Postgres
  • 是否需要存储过程 / 触发器复杂逻辑?需要 → Postgres / MySQL
  • 数据量预估 < 100 GB → SQLite 无障碍;> 1 TB → 考虑 Postgres 或分库
  • 团队是否有 DBA 资源?没有 → 优先 SQLite(运维成本几乎为零)
  • 不确定就先 SQLite,遇到瓶颈再迁——比反过来便宜得多

SQLite 不和 Postgres 竞争。它取代的是”fopen() + 自己造存储格式”。在它的目标场景里,是 Postgres 不能替代的。

❓ 常见问题

SQLite 真的能上生产吗?哪些大公司在用?

能,且部署量是世界第一SQLite 官方数据:(1) 每台 iOS / Android 手机至少有数百个 SQLite 库——通讯录、浏览器历史、应用配置;(2) 每个浏览器都用 SQLite——Chrome / Firefox / Safari 的本地存储;(3) macOS / Windows 系统组件也用。生产案例:(1) Notion——客户端用 SQLite 做本地缓存、离线编辑;(2) ChatGPT 桌面版——SQLite 存对话历史;(3) Slack 桌面端——SQLite 缓存消息;(4) expensify——后端核心账务库(高 TPS);(5) PocketBase / Litestream / Turso / Cloudflare D1——SaaS 围绕 SQLite 建生态;(6) fly.io 的 LiteFS——SQLite 多机复制方案。误解来源:(1) "SQLite 只是单文件,不能高并发"——确实写并发受限,但读并发非常强(多进程同时读零阻塞);(2) "SQLite 没有用户权限"——属实,但嵌入式应用不需要;(3) SQLite 官方的态度:它不和 Postgres 竞争,"appropriate uses for SQLite" 文档明确说哪些场景适合(嵌入式、单机服务、读多写少)哪些不适合(高并发写、多机分布式、需要复杂权限)。

SQLite 能撑多少并发?写入瓶颈在哪?

读并发几乎无限,写并发严重受限核心约束:SQLite 的写入是整库串行——同一时间只有一个写者,靠"writer 锁"保证。WAL 模式后(journal_mode=WAL):(1) 读不阻塞写、写不阻塞读;(2) 写者仍然只能 1 个,但读者可以无数个;(3) 实测中等硬件上可达每秒 5000-50000 次写(看事务大小、磁盘速度、是否批量)。默认 rollback journal 模式:读和写互斥,性能差很多,生产环境必须切 WAL典型并发上限:(1) 写 < 100 TPS——SQLite 完全够,无需调优;(2) 写 100-1000 TPS——SQLite + WAL + 适当 PRAGMA(synchronous=NORMAL)能撑;(3) 写 1000-5000 TPS——SQLite 极限,需要批量事务(BEGIN ... COMMIT 包多条)+ 仔细调优;(4) 写 > 5000 TPS——考虑 Postgres / MySQL 或分库。读 TPS:单机 SQLite 读可达 10 万-100 万 QPS(缓存命中时),瓶颈在 CPU 和磁盘 IO。实务:(1) "并发用户数"和"写 TPS"不是一回事——10000 在线用户但写很少(如 SaaS 阅读为主)SQLite 完全可以;(2) Web 应用瓶颈通常在网络 / 渲染,数据库不是;(3) 不确定就先用 SQLite,遇到瓶颈再迁。

SQLite vs PostgreSQL 最大的差异在哪?

部署模型 + 并发模型 + 类型系统部署:(1) SQLite——嵌入式,进程内库,无网络服务,单文件;(2) Postgres——独立服务进程,TCP 监听,需要起 server。并发:(1) SQLite——整库写串行(一个 writer),WAL 后读无锁;(2) Postgres——MVCC 多版本并发控制,多写者并行(每行级锁)。类型系统:(1) SQLite——动态类型("type affinity"),列类型只是建议,存什么都行;(2) Postgres——强类型,DECLARE 什么类型就只能存什么。事务隔离:(1) SQLite——SERIALIZABLE 默认(强一致);(2) Postgres——READ COMMITTED 默认,可调到 SERIALIZABLE(性能下降)。SQL 功能:(1) SQLite——支持 CTE、窗口函数、JSON1、FTS5、R-Tree、UPSERT;(2) Postgres——支持更多——存储过程、触发器、自定义函数、扩展(PostGIS / TimescaleDB)、partial index、并行查询。复制 / 高可用:(1) SQLite——原生没有,需要第三方(Litestream / LiteFS / rqlite);(2) Postgres——内置流复制、逻辑复制、Patroni / repmgr 高可用。实务:(1) 单机服务、嵌入式、桌面 / 移动 → SQLite;(2) 多机集群、高并发写、需要复制 / 分片 → Postgres / MySQL。

SQLite 单文件能大到多少?几十 GB 还能用吗?

理论上限 281 TB,实际几百 GB 完全没问题官方限制:(1) SQLITE_MAX_PAGE_COUNT 默认 4294967294 页 × 默认 4096 字节 = 16 TB;(2) 编译时调高 page size 到 65536 字节,上限 281 TB;(3) 这是单库文件大小,不是表行数限制(行数无限)。实际生产案例:(1) Expensify 公开过单库几百 GB稳定运行;(2) 个人项目 100 GB 级 SQLite 库很常见(爬虫存储、日志聚合);(3) Mozilla 的 Telemetry 数据库历史上达到 几 TB大库的注意事项:(1) VACUUM 慢——重建索引和回收空间在大库上要小时级,建议用 PRAGMA auto_vacuum=INCREMENTAL + 定期 incremental vacuum;(2) 备份要 hot backup——直接复制 .db 文件不安全(写入中可能损坏),用 .backup 命令或 sqlite3_backup API;(3) WAL 文件可能很大——长事务不 commit 会让 WAL 无限增长,定期 checkpoint;(4) mmap_size 设大点(>= 文件大小)能让 OS 自动管理缓存;(5) 索引内存占用——百万行表的索引可能几 GB,要 cache_size 足够。实务:(1) < 10 GB 不用特别优化;(2) 10-100 GB 配好 PRAGMA + 定期 VACUUM + 监控 WAL 大小;(3) > 100 GB 考虑分库(按时间 / 用户 ID hash)。

SQLite 备份怎么做最稳?能直接复制 .db 文件吗?

不能直接 cp,必须用 SQLite 自己的备份机制问题:直接 cp main.db backup.db 在写入过程中会复制到不一致的状态——头部页和后面的页可能来自不同事务,恢复时报 "database disk image is malformed"。正确方法:(1) .backup 命令(CLI)——sqlite3 main.db ".backup backup.db",在线热备份,不阻塞写;(2) VACUUM INTO(3.27+)——VACUUM INTO 'path/to/backup.db',输出重建后的紧凑库;(3) sqlite3_backup_* API(编程)——增量复制,可控制速度避免压垮源库;(4) WAL checkpoint + 文件复制——先 PRAGMA wal_checkpoint(FULL) 把 WAL 合并回主库,然后短暂阻塞写复制——简单但有锁定时间。Litestream / LiteFS:(1) Litestream 持续把 WAL 增量推到 S3 / B2,秒级 RPO;(2) LiteFS 是文件系统层的 SQLite 复制,多机一致;(3) Cloudflare D1 / Turso 用类似机制做托管 SQLite。陷阱:(1) 多进程读写时简单复制几乎一定坏;(2) 备份完一定 PRAGMA integrity_check 验证;(3) 加密库(SQLCipher)备份要带原密钥重建;(4) 不要依赖 OS 文件系统快照(LVM / ZFS)——除非快照前 fsync + 加全局写锁。实务:(1) 桌面 App → 退出时 .backup 一次;(2) Web 服务 → Litestream 持续推 S3;(3) 关键业务 → 双地热备 + 定期演练恢复。

什么场景一定不要用 SQLite?

5 类硬不适合的场景。(1) 多机分布式集群——SQLite 是单文件单机数据库,多机方案(rqlite / Dqlite / LiteFS)有但都是绕弯,原生场景请用 Postgres / CockroachDB / TiDB。(2) 高并发写(> 5000 TPS)——单 writer 锁是物理瓶颈,不是调优能解决的;秒杀 / 实时交易系统不要用。(3) 多租户 SaaS 的强权限隔离——SQLite 没有 GRANT / 用户系统,靠应用层做 RBAC;如果需要数据库层权限就用 Postgres。(4) 复杂的存储过程 / 触发器逻辑——SQLite 触发器有限,没有存储过程,复杂业务逻辑必须放应用层;如果团队习惯把逻辑下放数据库,用 Postgres / MySQL。(5) 跨数据中心同步 / 异步复制——SQLite 没有内置流复制,复杂场景下用 Postgres + 物理复制或 PgBouncer 集群更省心。灰色区:(1) 大数据分析——SQLite 能做但效率低,分析场景用 DuckDB / ClickHouse / Snowflake;(2) 时序数据——可以用,但 TimescaleDB / InfluxDB 更专业;(3) 图数据库——SQLite 用 CTE 能玩图查询但性能差,专业场景用 Neo4j / DuckDB PGQ。适合 SQLite 的核心场景:(1) 嵌入式 App(桌面、移动、IoT);(2) 单机服务 / CLI 工具;(3) Web 应用读多写少(个人博客、文档站、内部工具、SaaS 单租户);(4) 原型 / MVP 阶段(用 SQLite 起步,规模真大了再迁);(5) 测试数据库(in-memory :memory: 模式)。

🗄️ 打开 SQLite 在线编辑 拖拽 .db/.sqlite 浏览·SQL 查询/增删改·导出 CSV/JSON/.db·本地不上传

📖 同一工具的其他教程