所有文章

2026-08-16

· Dylan Yu
SQLitePostgreSQLdatabasearchitecture

SQLite vs PostgreSQL:如何为下一个项目选择合适的数据库

SQLite 和 PostgreSQL 解决的是不同的问题,但网上大多数建议都把其中一个说成普遍更好。这里有一套实用的决策框架,基于你实际在构建什么——并发、规模、部署,以及什么时候你可能两个都需要。

有个问题我见过无数次的糟糕回答:"我该用 SQLite 还是 PostgreSQL?"

典型的回答差不多就是"SQLite 用来做原型,PostgreSQL 用来上生产"。这不仅是过度简化——它还会误导人。它让人为了一个单用户的 CLI 工具去搭一个 Postgres 服务器(大材小用),或者把 SQLite 作为多写入 SaaS 的主数据库(迟早出事)。

诚实的答案是,它们各自为根本不同的场景做了优化。正确的选择取决于你工作负载的具体特征,而大多数对比文章从来不问这些。我们来逐一过一遍。

核心区别(大多数对比文章都跳过的)

SQLite 是一个。你把它链接到你的应用进程里,它读写磁盘上的一个文件。没有服务器,没有网络,没有认证握手。你的应用和数据库在同一个进程里。

PostgreSQL 是一个服务器。它作为独立的守护进程运行,管理自己的内存和连接池,通过网络协议接收查询。你的应用作为客户端连接到它。

这一个架构差异几乎解释了人们争论的所有其他差异:

  • 并发 — Postgres 用 MVCC 处理数百个同时连接。SQLite 通过一个全局锁来串行化写入(即使在 WAL 模式下)。
  • 部署 — SQLite 就是 npm install better-sqlite3,搞定。Postgres 是一个你需要运行、监控、备份并保持存活的服务器。
  • 规模 — Postgres 为跨多块磁盘的 TB 级数据而设计。SQLite 为单机上的 GB 级数据而设计。
  • 延迟 — SQLite 查询是微秒级的,因为没有网络往返。Postgres 查询是毫秒级的,因为总有一跳网络(即使在 localhost 上)。

这些都不意味着哪个"更好"。它们让其中一个对特定工作负载更合适

什么时候该用 SQLite

1. 单进程应用

如果你的应用作为单个进程运行——CLI 工具、桌面应用、移动应用、单服务器 webhook 处理器——SQLite 几乎总是正确的默认选择。当只有一个客户端时,单独的数据库服务器没有任何好处。

我会毫不犹豫地选择 SQLite 的场景:

  • 需要本地存储的桌面应用(BaseVolt 自己就用 SQLite 存配置)
  • 在多次运行之间跟踪状态的 CLI 工具
  • 移动应用(SQLite 已经内嵌在 iOS 和 Android 里)
  • 你还不知道 schema 的原型或 MVP
  • 由预计算的 .db 文件支撑的读多分析型 dashboard

2. 嵌入式和边缘场景

SQLite 的"无服务器"特性在边缘端变成了超能力。Cloudflare D1 就是跑在 Cloudflare 边缘网络上的 SQLite。Turso 和 libSQL 是为分布式读取优化的 SQLite 分支。如果你在构建靠近用户运行的东西——CDN 边缘上的 worker、IoT 设备、嵌入式系统——SQLite 是唯一合理的选择。Postgres 没法以一种你想维护的方式跑在 Raspberry Pi Zero 上。

3. 读多、低写入竞争的工作负载

有个让人意外的事实:WAL 模式下的 SQLite 可以处理数千个并发读取者,没有竞争。读取者不阻塞写入者,写入者也不阻塞读取者。限制只在并发写入——一次只能有一个写入者。

如果你的工作负载 99% 是读取(CMS、产品目录、配置存储、基于预计算数据的分析 dashboard),SQLite 能比你想象的扩展得更远。"SQLite 不能扩展"这个说法主要是针对写多的多用户应用,不是读多的。

4. 当你不想运维数据库的时候

这一点被低估了。在生产环境跑 Postgres 意味着:

  • 设置连接池(PgBouncer 或内置池化器)
  • 配置 shared_bufferswork_memmax_connectionswal_level
  • 设置自动备份并测试恢复
  • 监控复制延迟、vacuum 膨胀、锁竞争
  • pg_upgrade 或逻辑复制升级大版本

如果你是独立开发者或没有专职 DBA 的小团队,以上每一项都是凌晨三点可能出问题的地方。SQLite 一个都没有。备份就是 cp database.db database.db.bak

什么时候该用 PostgreSQL

1. 多进程或多服务器工作负载

当你有两台应用服务器需要读写同一份数据的那一刻,SQLite 就出局了。你可以把 SQLite 文件放在网络共享上,但你不应该这么做——NFS/SMB 上的文件锁是个定时炸弹,迟早会损坏你的数据库。

Postgres 正是为这种场景设计的。多台应用服务器连接到一个 Postgres 实例,Postgres 正确处理并发。如果你运行多个应用副本,你需要一个服务器端数据库。

2. 高写入并发工作负载

如果你有数十个并发写入者——有活跃用户的 SaaS、日志管道、实时分析入库——SQLite 的单写入者锁就成了瓶颈。即使在 WAL 模式下,写入者也要排队。Postgres 用 MVCC 处理这个:多个写入者可以同时修改不同的行,冲突在提交时解决。

经验法则:如果"来自不同进程的并发写入"是你工作负载的核心特征,你需要 Postgres(或 MySQL,或其他服务器端 RDBMS)。

3. 你真正需要的高级 SQL 功能

Postgres 有 SQLite 没有的功能,其中一些很重要:

  • 窗口函数 — SQLite 现在也有了,但 Postgres 的实现更完整
  • 物化视图 — Postgres 原生支持;SQLite 没有
  • 全文搜索 — 两者都有 FTS,但 Postgres 的 tsvector/tsquery 更强大
  • JSON/JSONB — 两者都支持 JSON,但 Postgres 的 JSONB 配合 GIN 索引完全不在一个级别
  • PostGIS — 如果你需要地理空间查询,PostGIS 是黄金标准
  • 逻辑复制、分区、LISTEN/NOTIFY — 服务器端功能,SQLite 没有对应物

上面关键词是*"你真正需要"*。大多数应用不用这些功能的大部分。但如果你在构建地理空间应用,或者需要通过 LISTEN/NOTIFY 做实时推送,或者在大规模查询嵌套 JSON,Postgres 就是答案。

4. 数据库层面的严格数据完整性

SQLite 以默认宽松著称。它使用动态类型——你可以往整数列里插入字符串,SQLite 会愉快地存下来。外键约束默认关闭(你必须在每个连接上 PRAGMA foreign_keys = ON)。Postgres 默认严格:类型不匹配会报错,外键被强制执行,约束不可商量。

如果你在团队中工作,希望数据库层面强制完整性而不是依赖应用代码,Postgres 的严格是功能,不是 bug。

对比表(附带诚实的权衡)

维度SQLitePostgreSQL
架构嵌入式库客户端-服务器
安装时间秒级(一个文件)分钟到小时(服务器配置)
并发读取者数千(WAL 模式)数千
并发写入者1(串行化)数百(MVCC)
实际最大容量单文件约 1TBTB+
网络延迟无(进程内)即使 localhost 也有 0.1-2ms
备份复制文件pg_dump / WAL 归档 / 快照
运维负担几乎为零不小
成本免费免费(自托管)或 $$(托管)
严格类型可选(默认动态)强制执行
JSON 支持JSON1 扩展JSONB 配 GIN 索引
全文搜索FTS5tsvector 带排序
地理空间有限PostGIS(同类最佳)
复制非内置(litestream 等)内置流式 + 逻辑复制
最适合单进程、边缘、读多多服务器、写多、复杂

实用决策框架

与其给你一个你会跳过的流程图,不如看这四个真正决定答案的问题。

1. 有多少进程会同时写入这个数据库?

  • 一个 → SQLite 没问题
  • 多于一个 → Postgres

2. 数据库会分布在多台机器上吗?

  • 不会,单机 → SQLite 没问题
  • 会,多服务器/副本 → Postgres

3. 你需要 Postgres 独有的高级功能吗(PostGIS、物化视图、大规模 JSONB、逻辑复制)?

  • 不需要 → SQLite 没问题
  • 需要 → Postgres

4. 你的团队运维数据库服务器的能力是约束条件吗?

  • 是,我们没有 DBA 也没时间 → SQLite(或托管 Postgres)
  • 不是,我们能跑 Postgres → Postgres

如果你对三个或更多问题回答了"SQLite 没问题",用 SQLite。如果你对两个或更多回答了"Postgres",用 Postgres。边缘情况比网上说的要少得多。

现实:很多团队两个都用

没人告诉你的是:选择不总是非此即彼。

我在运行良好的团队中见过一个常见的生产模式:

  • PostgreSQL 作为主操作数据库(多服务器、高写入、事实来源)
  • SQLite 作为本地缓存、边缘副本或单机上的分析快照

Cloudflare D1(边缘 SQLite)配合 Postgres 主库是全球分布式应用的合理架构。Turso + Postgres 是同样的思路。你写入 Postgres,复制到靠近用户的 SQLite 实例,以零延迟在本地读取。

这种设置的摩擦不在数据库——而在工具。大多数管理面板只为其中一种而建。你最终用 DBeaver 连 Postgres,用 DB Browser 连 SQLite,每种的工作流完全不同。

这也是我们构建 BaseVolt 同时支持两者的原因之一。指向一个 .db 文件用于 SQLite,或给它一个 Postgres 连接字符串,你就得到相同的管理界面——网格视图、kanban 看板、dashboard、关系配置——无论连接的是哪个数据库。对于同时使用两者的团队,这意味着一个工具而不是两个。(如果你想先看看再安装,demo.basevolt.app 有在线演示。)

我见过的常见错误

因为"更简单"而用 SQLite 做多写入 SaaS。 它确实更简单——直到你的第二个用户和第一个用户同时写入,你碰到了 SQLITE_BUSY。我在生产环境见过这个。用 Postgres。

为单用户 CLI 工具搭 Postgres。 你现在有了一个需要备份、监控和升级的数据库服务器,服务的是一个一个人用的应用。用 SQLite。

因为"不能扩展"而否定 SQLite。 它能扩展到数百 GB 和数千并发读取者。它不能做的是多进程并发写入。如果那不是你的工作负载,SQLite 扩展得比你想象的远。

把 Postgres 默认配置当生产就绪。 不是。max_connections = 100 不带连接池在任何真实负载下都会出问题。如果你跑 Postgres,了解 PgBouncer、shared_bufferswal_compression——或者用托管服务(Neon、Supabase、RDS)帮你处理这些。

总结一下

SQLite 和 PostgreSQL 不是竞争者。它们是做不同工作的工具。

  • SQLite 用于数据库和应用在一起:桌面应用、移动应用、边缘函数、CLI 工具、读多的单服务器工作负载、原型。
  • PostgreSQL 用于数据库服务多个客户端:多服务器 web 应用、高写入并发工作负载、需要高级 SQL 功能的应用、数据库层面严格完整性很重要的任何场景。

错误的做法是根据哪个"更强大"来选。根据你的工作负载实际做什么来选。大多数应用不需要数据库服务器。有些应用没有就不行。知道哪个是哪个才是真正的技能。

如果你在用其中之一(或两者),BaseVolt 给你一个本地优先的 SQLite 和 PostgreSQL 管理面板,不把你的数据发到任何地方。 无需账号,无需云端,离线可用。


在用 SQLite 或 Postgres 做东西?我很好奇你在做什么——在 X 上找我。

BasevoltBasevolt

试试 Basevolt —— 免费的本地优先数据库管理面板,支持 PostgreSQL、MySQL、SQLite 和 Cloudflare D1。

免费下载 Basevolt