SQLite WAL 预写式日志机制
WAL 是 Write-Ahead Logging(预写式日志)的缩写,是 SQLite 从 3.7.0 版本开始提供的一种替代传统回滚日志(Rollback Journal)的事务机制。
简单来说,WAL 模式的核心思想是 “修改先写日志,数据后落盘”。
🔄 核心原理:WAL 如何工作
要理解 WAL,可以先看看它取代的传统方式。
-
传统回滚日志模式:在修改数据前,先将原始数据页备份到回滚日志中,然后直接修改数据库文件。如果事务失败,用备份恢复原状;如果成功,则删除日志。这种方式的问题是,写操作会直接修改主数据库文件,导致读写操作互相阻塞,并发性能较差。
-
WAL 模式:工作流程完全不同:
- 写入日志:所有修改不直接写入主数据库文件,而是追加到一个独立的 WAL 文件(后缀为
-wal)末尾。 - 读取数据:读取数据时,SQLite 会先检查 WAL 文件,读取最新的修改;如果 WAL 中没有,再去主数据库文件读取。这种方式使得读操作和写操作可以完全并发执行,互不阻塞。
- 检查点(Checkpoint):将 WAL 文件中的修改批量应用回主数据库文件的过程。SQLite 默认会在 WAL 文件积累到约 1000 页时自动执行,也可以手动触发。
- 写入日志:所有修改不直接写入主数据库文件,而是追加到一个独立的 WAL 文件(后缀为
为了协调多进程/线程的读写,SQLite 在 WAL 模式下还会创建一个共享内存文件(后缀为 -shm)。
🚀 主要优势
- 更高的并发性:读写互不阻塞,显著提升多线程/进程环境下的并发性能。写操作之间仍然是串行的。
- 更快的写入速度:将随机写转变为顺序追加写,I/O 操作更高效。同时,
fsync()系统调用更少,降低了因磁盘同步导致的风险。 - 更强的数据恢复能力:系统崩溃后,SQLite 能通过读取 WAL 文件自动恢复已提交但尚未落盘的事务。
⚠️ 注意事项与限制
- 网络文件系统限制:所有访问进程必须在同一台主机上,WAL 模式不支持网络文件系统。
- 额外文件:每个数据库会多出
-wal和-shm两个文件。 - 页面大小不可变:进入 WAL 模式后,无法再更改数据库的页面大小(Page Size)。
- 多数据库事务:如果使用了
ATTACH命令附加了多个数据库,事务无法保证在所有数据库上的原子性。 - 极端的只读场景:在绝大多数是读操作、几乎不写入的应用中,WAL 可能比传统模式慢 1%-2%。
- 超大事务:对于超过 100MB 的大事务,传统回滚日志模式可能更快。
🛠️ 如何开启 WAL
在 SQLite 命令行或代码中执行以下 PRAGMA 命令即可开启:
PRAGMA journal_mode=WAL;
执行成功后,该命令会返回 wal。你也可以随时用以下命令检查当前模式:
PRAGMA journal_mode;
提示:开启 WAL 模式是持久化的,它会一直生效,直到你再次更改。
💎 总结
WAL 是 SQLite 官方推荐的一种高性能、高并发的事务处理模式。如果你的应用读写并发较高,或写入操作频繁,强烈建议开启 WAL 模式以获得性能提升。如果你的应用极其简单(单线程、极少写入),或数据库文件需要放在网络共享盘上,则使用默认的回滚日志模式可能更合适。