SQLite到底能不能支撑一个小型网站?

先给配置,因为绝大多数"SQLite 不行"的抱怨,最后都能追溯到这两行没设:

sql
PRAGMA journal_mode = WAL;
PRAGMA busy_timeout = 5000;

默认的回滚日志模式下,写操作会锁住整个库,读者全部被挡在外面。切到 WAL(Write-Ahead Logging)之后,读不阻塞写、写不阻塞读,这是完全不同的两种表现。

busy_timeout 解决的是另一件事:拿不到写锁时,默认行为是立刻抛 SQLITE_BUSY;设了 5000 毫秒,它会先等 5 秒再放弃。对小型站来说,这一等就把绝大多数"并发报错"消掉了。

能。但要清楚它卡在哪儿。

天花板不是数据量,是写入并发

SQLite 常被误以为"只能撑小数据量",这是个误会。官方 limits 页面给的单个数据库文件上限是 281 TB,实际项目里没有谁先撞到这条线。

真正的约束在别处:写操作始终只有一个写者。所有 INSERT、UPDATE、DELETE 串行执行,一次一个。WAL 让读可以并发,写不行。

换算成可感知的量级:读请求随便几千 QPS,只要库文件在 SSD 上、命中页缓存,几乎没有瓶颈。写请求一旦形成持续排队——比如每秒几十次以上的写入且每次事务较长——才开始出问题。

小型站的写入量通常远低于这个数。一个工具站可能一天几百次写,一个带用户系统的 SaaS 可能每分钟几十次。这两个量级 SQLite 都能扛。

读多写少是它的主场,而小网站大多如此

Inch Calculator 2026 年 6 月的估算访问量是 459 万。这类站的请求构成极其偏读:用户打开页面、看结果、走,写入几乎为零(最多记一条统计)。

Inch Calculator 官网首页截图
Inch Calculator 官网首页截图

Inch Calculator 首页写着 3500+ 个免费计算器,按汽车、建筑、烹饪等场景分卡陈列。

Homewyse 是另一个例子,42.885 万访问,做的是装修报价——材料、人工、报价拆开算。这类计算型页面每次请求最多读几次配置表,不存在写压力。

对这种负载,SQLite 反而比独立数据库服务更合适:没有网络往返、没有连接池、没有独立进程要监控。一次查询的耗时就是一次本地函数调用。

Cakedesk 把它推到了极端:数据库在用户电脑上

Max Schmitt 做的 Cakedesk 是个桌面端发票应用,Electron 加 React 加 Node.js,数据全部存在用户本机(SQLite 或等价的本地文件存储)。

一次性 €69,没有订阅。2024 年卖出约 170 份,2025 年卖出 239 份新授权,毛收入约 16000 欧元。它连"服务端数据库"这个概念都不存在——每个用户一个库,天然隔离,天然没有并发问题。

这个架构的代价也很明确:没有服务端就做不了跨用户的功能,多设备同步、团队协作都别想。但它证明了另一件事——对很多小产品来说,"多个小库"比"一个大库"简单得多

算一笔具体的容量账

拿一个真实量级估算:一个小型站每天 5000 次写操作,平均分散在 8 个小时里,约合每秒 0.17 次。一次写事务在本地 SSD 上通常几毫秒完成。

也就是说,单写者那把锁的占用率不到百分之一。这个距离"写锁顶住"还差着两个数量级。

读的那一侧更宽松。WAL 模式下读者完全不被写阻塞,只要库文件在 SSD 上、热点页在缓存里,几千 QPS 是轻松的。Inch Calculator 2026 年 6 月 459 万访问、Homewyse 42.885 万访问,落在数据库上的读压力对本地文件来说毫无压力。

另外要注意读的性能和数据量的关系不大,和页缓存命中率关系很大——库文件比可用内存大很多之后,随机读会明显变慢。这时候加内存比换数据库划算。

真正会出问题的场景是另一个:一个长事务持锁不放——比如批量导入几万条数据没分批——这时所有其他写都会被挡住。解决办法不是换数据库,是把大事务拆成小批。

什么时候必须换掉它

四个信号,出现任意一个就该认真考虑独立数据库服务:

一是出现多机写入。两台以上服务器要写同一个库时,单文件方案失效——除非你把写全部收拢到一台机器上,但那台就变成了单点。

二是写并发持续顶住写锁。busy_timeout 已经设了但日志里仍频繁出现 SQLITE_BUSY,说明写入量超过了单写者的能力。

三是需要复杂的在线 DDL。SQLite 的 ALTER TABLE 支持有限,大改表结构时要走"建新表、搬数据、改表名"这套流程。

四是需要细粒度权限和审计。多个人要连同一个库、各自只看一部分数据时,独立数据库服务的账号体系是必需的。

在此之前换,等于提前背上一份没有回报的运维工作。

备份比想象的简单

一个文件的好处在这里彻底兑现。热备份一条命令:

sql
VACUUM INTO 'backup-2026-09.db';

它在库正常服务的同时产出一个紧凑的完整副本。定时跑一次、把文件传到对象存储,一套备份方案就成了。

如果要求更细的恢复粒度(比如能回到任意一秒),可以上 Litestream 这类工具,把 WAL 的变更持续复制出去。部署时把库放在持久卷上,Docker 的 volume 配置要单独写清楚——容器重建时数据不能跟着没了,这是最容易出事的一处。

默认从它起步,把换掉的条件写成指标

新项目默认从 SQLite 起步,开 WAL 和 busy_timeout,配好 VACUUM INTO 的定时备份。把"什么时候换"写成可观测的指标——比如写事务的等待时间——而不是凭感觉判断。

Data Fetcher 是这条路走通的例子:Andy Cloak 一个人在伦敦运营,Airtable 扩展,600 个付费客户、MRR 23000 美元。一人公司的产品规模可以远超"小项目"这三个字,而底层的存储方案往往比你以为的保守得多。你的站现在每秒有几次写?