茜莉娅 Serelia
← Back to the beginning

WAL架构下的SqLite

技术笔记
数据库

小记

最近在开发中偶然遇到了几种数据库设计之一:WAL模式。

SQLite 的 WAL(Write-Ahead Logging,预写式日志) 与传统的“回滚”日志的概念截然相反。 它注重于修改数据时,不直接写入主数据库文件,而是先将变更追加到一个单独的 .db-wal 文件中。只有在事务提交后,这些变更才会在某个时间点被合并回主数据库文件。[1]

模式如下:

展开图表

WAL模式并发性的根本是基于“读写操作交互”的改变。

  • 写操作:数据库事务进行的时候,所有修改顺序都追加到.db-wal后缀,与数据库文件同名的一个文件的末尾,一个愿意是避免了随机写入主.db 文件,使磁盘I/O 更有顺序。
  • 读操作:当读事务开始的时候,它选择记住当前“WAL”文件的状态快照,并只修改在这个快照以前已经提交过的数据。后续其他事务的写入,对它来说完全透明。

由此:WAL实现了“读不阻塞写,写不阻塞读”的概念,读写可以同时进行。

检查点

WAL基于检查点机制并不会无限生长,检查点机制会在每一个检查点,将yourdbName.db-wal文件中已提交更新的数据合并到主库。

  • 手动控制:你可以选择主动PRAGMA wal_checkpoint;命令来手动设置检查点。

注意:文件构成变化 启用 WAL 后,数据库会关联 .db-wal 和 .db-shm(共享内存索引)文件。所以说删除或移动数据库时,必须同时处理这三个文件,单独保留主文件可能导致数据库损坏或状态不一致。

不支持大型事务:WAL 模式在处理非常大的事务时表现不佳,因为整个事务的变更都会堆积在 WAL 文件中。

无法更改页面大小:一旦进入 WAL 模式,就无法再修改数据库的 page_size,必须先切换回其他日志模式才能更改。

纯读场景额外开销:如果一个应用几乎只有读操作,WAL 模式可能比传统模式慢 1%-2%,因为读操作需要额外检查 WAL 文件。

fsync()

那正好借着这个机会说一下一款系统调用:fsync。

  • 函数签名:int fsync(int fd);

Describe:fsync() 是 Unix/Linux 下的一个系统调用。

作用:把某个文件描述符对应的文件数据和元数据,从操作系统内核的页缓存**(page cache)强制刷写到持久化存储设备并等待刷写完成**后才返回。


它的调用有一种含义:调用成功后,表示该文件此前写入的数据,以及相关必要的元数据已经被安全落盘到存储设备当中。

  • 在fsync() 成功返回前,任何操作都不会被试作为一种成功“落盘”。

  1. https://cloud.tencent.com.cn/developer/article/2438300?from=15425&policyId=undefined&traceId=&frompage=seopage#1 ↩︎

© 泠時月 2026,采用 CC BY 4.0 许可,转载保留署名。

留言 · 0 段对话

© 2026 茜莉娅 · Powered by Serelia 茜莉娅 88x31 徽章

扫码分享

二维码