用过 MySQL、PostgreSQL、MongoDB、SQLite、LevelDB、Redis、Memcached 之后,我现在做小项目的默认选型是 SQLite

不是退步。

是打了足够多的架,才知道什么时候该收刀。


一张表看懂选型逻辑

在展开之前,先给核心结论——不是「SQLite 万能论」,是按场景切

阶段推荐理由
MVP / 原型SQLite0配置,代码即数据库
单人/3人内小SaaSSQLite并发够用,运维≈0
桌面+移动端SQLite原生嵌入,无可替代
嵌入式/IoTSQLite最小的完整SQL引擎
数据分析/ETLSQLite.import .mode csv,秒杀Python+pandas
多节点/高并发写PostgreSQL到这步才需要,但先别急

下面逐条拆。


1. SQLite 被低估到什么程度

大多数人听到 SQLite 的反应:"玩具数据库吧?"

不夸张地说,SQLite 是地球上部署最广泛的数据库引擎。每部手机、每台 Mac/Windows、每架波音787的航电系统、大多数车载娱乐系统、无数嵌入式设备——里面都嵌着 SQLite。年部署量超过 1万亿份

你口袋里就跑着一个 SQLite,而你甚至不知道。

这不是「玩具」,这是经受过最严苛环境验证的生产级嵌入式数据库

MySQL 和 PostgreSQL 的定位是 C/S 架构,需要独立进程、配置调优、连接管理。SQLite 的定位是零配置、零运维、嵌入应用内部。这是设计哲学的根本差异,不是性能差距。


2. 小项目的瓶颈从来不是数据库

做一个日活20人的内部工具、博客系统、小型SaaS——你的瓶颈在哪儿?

  • 开发速度
  • 部署复杂度
  • 运维成本

没有一条是「数据库不够强」。

你花两天配置 PostgreSQL,写 docker-compose,调 shared_buffers,配 pg_hba.conf,设置连接池——这些时间本来可以写两天的业务代码。

而用 SQLite:pip install pysqlite3 或者 go get github.com/mattn/go-sqlite3,写 SQL,跑起来。

差的是两个数量级的启动成本。


3. SQLite 够用的四个场景(逐一拆)

场景一:单机 Web App

Web 应用的典型模式是:少量写入(用户操作)、大量读取(展示内容)。

SQLite 在 WAL(Write-Ahead Logging)模式下,读写不互斥。实测单机并发写入能达到 每分钟几千次(约 50-100/s)。对绝大多数小项目来说,这个数字已经超出需求两三个数量级。

你说不够?先看看你项目的活跃用户数。日活1000的博客系统,每分钟产生的写入数大概率不超过两位数。

场景二:MVP / 原型验证

创业里最怕的不是选错技术栈,是投入量级错了

你用 PostgreSQL 搭了个 MVP,花了三周配置部署集群。然后发现需求错了,方向错了,甚至项目死了。这三周是纯沉没成本。

用 SQLite 搭 MVP:写三天代码,直接上线。用户验证失败?删掉重来,成本约等于零。

MVP 阶段的目标是验证需求,不是验证架构。

而且——"先上 PG 以后再迁" 这个论调最大的问题是:你根本不会去迁。等项目管理后台、用户系统、订单流程全跑在 PG 上之后,不可能因为"架构更干净"就去重写一遍。

场景三:嵌入式/IoT/边缘设备

树莓派、路由器、工业控制器、车载系统——这些场景的硬件资源是寸土寸金。

PostgreSQL 初始化就要几百 MB 内存,而 SQLite 的二进制体积不到 1MB,内存消耗动态调节。在 IoT 场景下,SQLite 不仅是够用,而是唯一合理的选择

场景四:桌面 + 移动端

这更不用争。Chrome/Firefox/微信/Telegram/Signal 全部内嵌 SQLite。移动端首选项是 SQLite + Room 或 WCDB。桌面端 Electron 应用里 SQLite 是最常见的本地存储方案。

这个市场 PostgreSQL 根本进不来——不是性能问题,是架构不匹配。


4. SQLite 的真实硬限制

我诚实地说 SQLite 的短板,不粉饰:

限制实际情况对策
并发写入上限 ~100/sWAL 模式下读写入不互斥,写入串行化但不阻塞读多数小项目碰不到上限
无用户权限管理没有 GRANT/REVOKE应用层鉴权
无网络协议SQLite 不是 C/S 架构这不是缺点,是安全设计——减少攻击面
存储上限 281TB单文件,理论上限大足够小项目用 "几辈子"
全文检索FTS5 模块原生支持比 MySQL 的全文索引好用

老实说,这些限制对 90% 的小项目来说,是学术问题,不是工程问题。

就像你开个便利店非要修一条八车道高速公路——不是路不好,是你不需要。


5. PostgreSQL 在小项目上的隐性成本

现在说反方——为什么小项目上 PG 不是"省心",是给自己埋运维炸弹

安装配置成本:

  • 需要独立服务进程(systemd + pg_ctl)
  • 配置连接池(pgbouncer 或应用层池)
  • 调优 shared_buffers、work_mem、effective_cache_size
  • 设置 pg_hba.conf(认证方式、IP白名单)
  • 初始化数据库(initdb、createuser、createdb)

这一套下来,新手照着文档走一遍至少半天。老手也要半小时。

运维成本:

  • 备份策略:pg_dump 还是 pg_basebackup?WAL 归档要不要开?
  • 版本升级:pg_upgrade 或 dump/restore,停机窗口
  • 监控:慢查询、连接数、死锁
  • 内存:PostgreSQL 启动后至少占用 200-300MB 空闲内存

心理成本:

  • 改个 schema 都要想"会不会锁表"
  • 连接池配置错了,应用挂掉
  • 磁盘满了、WAL 日志炸了、复制延迟了

这些对一个日活50人的小 SaaS 来说,全是没必要的负担


6. "先上 PG 以后不用迁" 是最大的谎言

这句话的逻辑漏洞:

第一,大多数项目根本活不到需要 PG 那一天。

数据很残酷:90% 的创业项目在18个月内死亡。你为了一个可能不存在的「高并发未来」,从第一天就开始承受 PG 的运维成本——这叫做没有概率思维

第二,活着的小项目也不会去迁。

一个小SaaS 跑在 PG 上已经稳定运行两年了。业务逻辑、查询语句、ORM 模型全部高度耦合。这时候你跟我说「应该从 SQLite 迁到 PG」——凭什么?

问题是,它本可以跑在 SQLite 上,且零运维。

第三,当项目真的需要 PG 时——迁就是了。

SQLite → PostgreSQL 的迁移工具有:pgloadersqlite3-to-postgres、甚至有 SQLite 的 dump → PG 的兼容模式。数据迁移是标准流程,不是技术难题。

真正难的是:你的业务逻辑写得一塌糊涂,数据库换十个也没用。


7. 什么时候该上 PostgreSQL

我不是 SQLite 原教旨主义者。该上 PG 的时候我第一个上。

诚实列出需要 PG 的场景:

  • 多节点 / 读写分离:应用需要在多台服务器上同时读写同一个数据库
  • 持续高并发写入:> 100/s 的持续写入(不是偶发尖峰)
  • 复杂查询需求:窗口函数、CTE 递归、物化视图、GIS
  • 团队有 PG 运维能力:如果你团队里有 DBA 专门管 PG,那用 PG 是合理的
  • 合规要求:某些行业审计要求数据库有用户权限体系

这些场景之外的,默认选 SQLite。等碰到天花板再换。


8. 实战推荐阶梯

我从一个项目从 0 到 10000 用户的完整选型路径:

阶段 0:想法 → 白板
  数据库:无
  工具:Markdown 文件

阶段 1:MVP(0-50 用户)
  数据库:SQLite
  部署:单进程,代码即部署
  备份:litestream 实时同步到 S3/OSS

阶段 2:增长(50-500 用户)
  数据库:SQLite + WAL
  部署:单机,加一层应用缓存
  备份:litestream + 每日文件备份

阶段 3:规模化(500-5000 用户)
  数据库:SQLite → 加只读副本或分片
  部署:多实例水平扩展
  备份:更频繁的快照

阶段 4:企业级(5000+ 用户)
  数据库:PostgreSQL / 分片数据库
  部署:集群 + 读写分离
  备份:WAL 归档 + PITR

现实是:绝大多数项目走到阶段 2 就足够了。 而对于一个工具类 SaaS,走到阶段 2 可能需要两年。

你猜那时候你是要忙着救火还是优雅迁移?


结语:选型不是选最强的

没有一个数据库能打所有仗。但一个工作了近20年的老朋友告诉我:

如果你不确定自己的项目未来有多大数据库需求,就选 SQLite。

当你有一天发现 SQLite 不够用了——这其实是个好消息,说明你的项目活到了那一天。

那时候你再考虑 PostgrSQL,而不是在项目还没上线时就开始担心「万一」。

创业和技术选型最大的共同错误:不是在变化发生时应对问题,而是在问题还没出现时就开始过度解决。

SQLite is enough. 先让它证明自己不够,再换。


P.S. 我还会继续用 PostgreSQL。团队需要一个可靠的 OLAP 数据库时,PG 是最稳的选择。但我的下一个个人项目的默认起点——一定是 SQLite。