SQLite 在 1GB 内存服务器上的调优笔记
单文件数据库在低配机器上其实非常能打,前提是把 WAL、缓存和同步策略这几个参数配对。附完整的 PRAGMA 配置和三个反模式。
#为什么在小机器上反而该用 SQLite
选型时最常见的误判是:认为 SQLite 是"玩具数据库",生产必须上 MySQL。
在单进程、单机、读多写少的场景下,SQLite 的实测表现反而更好:
- 零额外内存:不占独立进程,MySQL 空跑也要 300 MB 起
- 零网络开销:没有 TCP 往返,读操作直接走文件页缓存
- 备份极简:就是一个文件,
cp或者走 backup API 都行
它真正的限制只有一条:写入是串行的,且不适合多主机共享。个人站点几乎不可能触到这条线。
#关键 PRAGMA 配置
初始化连接时执行这几条,顺序也重要:
const db = new Database('data/blog.db');
db.pragma('journal_mode = WAL'); // 必须第一个执行
db.pragma('synchronous = NORMAL');
db.pragma('busy_timeout = 5000');
db.pragma('cache_size = -20000'); // 负值单位为 KiB,即约 20MB
db.pragma('temp_store = MEMORY');
db.pragma('foreign_keys = ON');
#journal_mode = WAL 到底改了什么
默认的 DELETE 模式下,写事务会锁住整个数据库,读操作必须等待。WAL(Write-Ahead Logging)改成"写日志文件、读快照",读写互不阻塞。
代价是会多出两个附属文件:
data/blog.db
data/blog.db-wal ← 预写日志
data/blog.db-shm ← 共享内存索引
这直接影响备份策略:不能只复制 blog.db,因为最新的数据可能还在 -wal 里。正确做法是用 backup API:
db.backup('/path/to/backup.db'); // 在线一致性快照,自动处理 WAL
#synchronous 该选哪个
这是性能与持久性的权衡点,三个选项的实际差别:
| 取值 | 写入速度 | 断电风险 | 建议 |
|---|---|---|---|
FULL |
1× | 几乎无 | 金融类数据 |
NORMAL |
约 3× | 可能丢最后几条已提交事务,数据库不会损坏 | 绝大多数场景 |
OFF |
最快 | 可能损坏数据库 | 不要用 |
WAL 模式下 NORMAL 已经能保证数据库文件本身不会损坏,最多丢最近几条写入。个人博客完全可接受。
#cache_size 的负值是什么意思
这是个容易看错的参数:
- 正值:单位是"页数",默认 2000 页 × 4 KB = 约 8 MB
- 负值:单位是 KiB,
-20000= 20000 KiB ≈ 20 MB
小库(几十 MB 以内)设成 -20000 基本可以让热数据全部驻留内存。但别超过 -30000,1 GB 的机器经不起。
#三个必须避开的反模式
#反模式一:多进程共享同一个库文件
WAL 模式依赖共享内存(-shm 文件),这个机制只在同一台主机内有效。
❌ PM2 cluster 模式开 4 个实例,共享一个 SQLite 文件
❌ 两个 Docker 容器挂载同一个 SQLite 文件
❌ SQLite 文件放在 NFS / 网络盘上
正确做法:单进程(PM2 fork 模式)。真需要多实例,说明该换 PostgreSQL 了。
#反模式二:热备份直接 cp
❌ cp blog.db backup.db # 可能复制到写入中的半截状态
✅ 用 backup API 或先停服务
如果一定要用 shell 脚本备份,正确姿势是先做 WAL checkpoint:
sqlite3 data/blog.db "PRAGMA wal_checkpoint(TRUNCATE);"
cp data/blog.db backup/blog-$(date +%F).db
#反模式三:给每个字段建索引
索引会让写入变慢、文件变大。SQLite 的查询优化器对单表小数据量本来就能全表扫得很快。
判断标准很简单:只给出现在 WHERE、ORDER BY、JOIN 里的高频字段建索引。可以用 EXPLAIN QUERY PLAN 验证索引有没有被真正用上:
EXPLAIN QUERY PLAN
SELECT * FROM posts WHERE status = 'published' ORDER BY published_at DESC;
输出里出现 USING INDEX idx_posts_status 才算生效。如果显示 SCAN posts,说明索引没被用上,白建了。
#相关资源
以下资料可直接下载:
数据自动备份脚本
每日定时备份站点数据库与附件目录,自动保留最近 14 天并输出清理日志,可直接配到宝塔「计划任务」。
#什么时候该考虑换掉 SQLite
出现下面任一情况,就该认真评估迁移:
- 需要多进程/多机写入 —— SQLite 的架构性限制
- 单表超过千万行且查询复杂 —— 查询优化器能力有限
- 需要真正的并发写入 —— 写锁是库级的
- 需要在线扩容/主从 —— 单文件做不到
对个人站点来说,这些基本都不会发生。不要为了想象中的规模提前付出复杂度成本。
配套的调优参数表可以在文末下载,直接改改就能用。
附件下载 共 1 个文件,点击直接下载
低配服务器 SQLite 调优参数表
1 GB 内存小机器上 SQLite 的推荐 PRAGMA 配置,含每一项的作用说明与副作用提示,可直接复制使用。