SQLite 的 WAL 模式:读不阻塞写,但先要搞清这三个代价

举报
yd_268445051 发表于 2026/11/01 09:59:16 2026/11/01
【摘要】 SQLite 的 WAL 模式:读不阻塞写,但先要搞清这三个代价SQLite 默认用回滚日志(rollback journal)模式:写事务提交时要先把旧数据写进日志,写期间读会被阻塞,读期间写也进不来。单进程、偶尔写一次的小工具用它完全够用;但一旦出现“一个进程持续写、另一个进程频繁读”的场景,默认模式的锁竞争就会变成肉眼可见的卡顿。WAL(Write-Ahead Logging)模式就...

SQLite 的 WAL 模式:读不阻塞写,但先要搞清这三个代价

SQLite 默认用回滚日志(rollback journal)模式:写事务提交时要先把旧数据写进日志,写期间读会被阻塞,读期间写也进不来。单进程、偶尔写一次的小工具用它完全够用;但一旦出现“一个进程持续写、另一个进程频繁读”的场景,默认模式的锁竞争就会变成肉眼可见的卡顿。WAL(Write-Ahead Logging)模式就是为这种场景准备的:写操作先追加到 WAL 文件,读操作继续读主数据库文件,两边不再互相堵。

开启只需要一行,但要理解它改了什么

import sqlite3

conn = sqlite3.connect("app.db")
conn.execute("PRAGMA journal_mode=WAL;")
# 返回 ('wal',) 即表示已切换;该设置会被持久化到数据库文件里

切换后,写事务的流程变了:新数据先写进 -wal 文件,提交时只做一次 fsync,主数据库文件本身暂时不动;读事务则在主文件和 WAL 文件之间做一次合并视图,读到的是“主文件 + 已提交 WAL 记录”的最新快照。检查点(checkpoint)发生时,WAL 里的已提交记录才会被批量写回主文件,WAL 文件随之截断或复用。

带来的直接好处是:读和写可以并发进行,一个长读事务不会挡住写事务提交,写事务也不会让读到一半的查询报错“database is locked”。对日志采集、埋点写入、本地缓存这类“写多读也多”的场景,WAL 几乎是必选项。

三个代价,启用前先想清楚

第一,WAL 文件会增长。检查点只在特定时机触发:最后一个连接关闭时、WAL 文件达到阈值(默认 1000 页)时、或手动执行检查点时。如果写进程一直开着连接、从不关闭,又没有读进程帮忙推进检查点,WAL 文件会越长越大,读事务每次都要扫描更长的 WAL,查询反而变慢。办法是定期手动检查点:

# 在写空闲时执行一次,把已提交记录写回主文件
conn.execute("PRAGMA wal_checkpoint(TRUNCATE);")

TRUNCATE 会把 WAL 清空并把文件截断到 0 字节,适合维护窗口期执行;日常运行中用默认的 PASSIVE 检查点就够了,不要在高并发写期间频繁做 TRUNCATE,那会重新引入写阻塞。

第二,WAL 模式下数据库不再是单个文件。app.db 旁边会多出 app.db-wal 和 app.db-shm 两个文件,备份、拷贝、打包时只拷主文件等于丢了最新提交的数据。备份前要先做一次检查点,或者用 SQLite 自带的在线备份 API;直接用文件复制工具热拷正在写的 WAL 数据库,是最常见的“备份出来是旧数据”来源。

第三,WAL 不适合网络文件系统。WAL 依赖共享内存(shm)和文件锁在多进程间协调,NFS、SMB 这类网络文件系统的锁语义不可靠,官方明确不建议在上面用 WAL。数据库放在网络盘上时,宁可退回默认日志模式,接受锁等待,也不要冒数据损坏的风险。

两条落地建议

第一,判断标准很简单:如果只有一个进程访问数据库,且读写基本不重叠,默认模式更简单、文件也只有一个;一旦出现多进程读写、或读事务较长,就切到 WAL,并给写空闲时段安排一次检查点。第二,WAL 不是“开启就不用管”:监控 -wal 文件大小,超过主文件几倍时就说明检查点没跟上,先查是不是有长读事务一直占着旧快照,再决定是关连接还是手动检查点。

WAL 把“读写互斥”换成了“检查点与文件管理”的新责任。理解这个交换,SQLite 才能在并发场景下既快又稳。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。