【SQLite 内核】WAL 与 checkpoint:追加日志与读写并发

💡 原文中文,约10400字,阅读约需25分钟。
📝

内容提要

SQLite WAL模式将改动追加至-wal文件,主文件不变,实现读写不互阻。checkpoint为必要操作,PASSIVE不缩文件,仅TRUNCATE截断至零。实测显示PASSIVE后主文件增大而WAL不变,TRUNCATE后归零。SQLite WAL与PostgreSQL WAL同名但机制不同,前者帧参与读路径,后者仅恢复用。权衡读放大与checkpoint频率仍为开放问题。

🔎

延伸解读

PASSIVE 与 TRUNCATE 的差异

实测显示,PASSIVE checkpoint 后主文件从 1 页涨到 5 页,但 -wal 文件大小不变;只有 TRUNCATE 才将 -wal 截断到 0 字节。这印证了官方文档:PASSIVE 只是搬移帧并允许覆写,不缩文件。因此,若需回收磁盘空间,必须显式使用 TRUNCATE。

WAL 与 PostgreSQL WAL 的本质区别

SQLite 的 WAL 帧是当前数据的一部分,读路径会按 end mark 在 WAL 与主文件间选择最新版本;而 PostgreSQL 的 WAL 是 redo 日志,仅用于崩溃恢复,不参与正常读。同名不同构造,理解这一点有助于避免混淆两者的恢复机制和性能特征。

checkpoint 与读放大权衡

官方文档仅给出定性建议:读快需勤 checkpoint,写快则让 WAL 长一些。没有通用最优周期公式。实际需根据工作负载(读写比例、长事务)调整 wal_autocheckpoint 阈值和手工调度。这是运维中仍需权衡的开放问题。

Q&A

SQLite WAL模式与传统的rollback journal模式在写入方式上有什么本质区别?

在rollback journal模式中,原始内容被备份到-journal文件,改动直接写入主数据库文件;而WAL模式正好相反,原始内容留在主文件不动,改动追加到独立的-wal文件中,提交时只需在WAL中写入一条带commit标记的帧,不需要碰主文件。

SQLite WAL模式如何实现读写并发?

WAL模式通过将改动追加到-wal文件,使写者不直接修改主文件,因此读者可以继续从主文件读取未修改的数据,同时写者可以并发追加帧。读事务开始时记录一个end mark,之后读取页面时先检查WAL中end mark之前是否有该页的更新版本,有则用WAL中的,否则用主文件的,从而保证一致性快照。

SQLite WAL模式中checkpoint的PASSIVE、FULL、RESTART和TRUNCATE模式有什么区别?

PASSIVE模式在不打扰其他连接的前提下尽量多搬,不保证完成;FULL模式更努力地跑到完成,会等待写者,但不重置WAL;RESTART在FULL基础上,完成后保证下一个写者能从WAL头部重新开始写;TRUNCATE在RESTART基础上再把WAL文件截断到0字节,是唯一会让-wal文件变小的模式。

为什么SQLite WAL模式中PASSIVE checkpoint后主文件变大但WAL文件大小不变?

PASSIVE checkpoint只是把WAL中的帧搬回主文件,但不会截断WAL文件,只是将写指针倒回WAL开头,允许后续事务覆写旧内容。因此主文件会增大,而WAL文件大小保持不变。只有TRUNCATE checkpoint才会真正将WAL文件截断到0字节。

SQLite WAL与PostgreSQL WAL有何不同?

两者只是同名。PostgreSQL的WAL是redo日志,用于崩溃恢复时重放日志,日志本身不参与正常读路径;而SQLite的WAL帧本身就是当前有效数据的一部分,读者在读取时可能同时从主文件和WAL中获取最新内容,WAL文件是常态化的数据存放位置之一。

SQLite WAL模式中-wal和-shm文件的作用是什么?

-wal文件存储追加的改动帧,是WAL模式的核心;-shm文件是wal-index的共享内存映射,用于加速页查找,默认不超过32 KiB,从不fsync。wal-index帮助读者快速定位WAL中的页面,避免线性扫描整个WAL文件。

SQLite WAL模式中自动checkpoint的默认阈值是多少?

官方文档写明默认行为是WAL达到约1000页时自动触发PASSIVE checkpoint。应用可以关闭自动checkpoint,但需要自己保证有别的机制定期搬运,否则WAL文件会无限增长。

SQLite WAL模式在哪些场景下不支持?

WAL模式依赖共享内存(-shm文件),因此只能在同一台主机上工作,不支持网络文件系统。此外,涉及多个ATTACH数据库的事务,WAL模式下每个数据库各自原子,但跨数据库整体不再保证原子性。

🏷️

标签

➡️

继续阅读