上次优化又崩了?SQLite WAL 怎么把 Codex 直接卡死?
应用本身出了问题
上周刚把 Codex 的对话加载速度从 6 秒优化到 88 毫秒,结果两天后桌面应用直接卡死。点击任意历史对话就假死,任务管理器显示“无响应”。终端里的命令行工具还能秒出数据,说明数据没坏,是应用本身出了问题。
排查:三个 SQLite 文件的秘密
Codex 的数据目录 ~/.codex 里有三个 SQLite 数据库:
state_5.sqlite(300KB):对话元数据(线程、标题、模型)logs_2.sqlite(70MB):运行日志goals_1.sqlite(24KB):目标任务
这些文件大小看起来都很正常,但真正的问题藏在同名的 WAL 文件里:
state_5.sqlite-wal(4.1MB):WAL 日志logs_2.sqlite-wal(4.2MB):同样是 4MB WAL
WAL 文件比主数据库大了 13 倍,这才是导致卡死的真凶。
什么是 WAL,为什么它会胀成这样?
SQLite 默认使用 WAL(Write-Ahead Log)模式。写操作不直接改数据库,而是先写到 WAL 文件;读操作需要同时查数据库和 WAL,合并最新结果;当 WAL 积累到一定大小,才会触发 checkpoint 合并回主数据库。
正常情况下这个过程对用户透明。但 Codex 桌面应用在运行期间持续高频写入(记录日志、更新状态),而 checkpoint 频率跟不上写入速度,导致 WAL 像滚雪球一样越来越大。
正常 WAL 通常只有几 KB,随时合并;Codex 的 WAL 却达到了 4MB,包含 870 页待合并数据。每次切换对话,应用读取 state_5.sqlite 时,SQLite 需要在 870 页 WAL 中逐页查找最新数据——870 次磁盘 IO,每次几百毫秒,UI 线程直接卡死。
解决方案
既然根因是 WAL 文件过度膨胀,解决思路就很明确了:定期清理 WAL + 控制写入频率。
最实用的做法是写一个一键启动器,启动 Codex 前先执行 WAL checkpoint,把积累的日志合并回主数据库。Windows 用户还可以设置定时任务,每隔 3 小时自动运行一次维护脚本。
同时建议在 Codex 配置里把日志级别从 TRACE 降到 INFO,减少不必要的写入。日志数据库从 70MB 降到 30MB 左右后,WAL 膨胀问题基本消失。
预防措施
- 定期检查
~/.codex目录下的.sqlite-wal文件大小,如果超过 1MB 就手动触发 checkpoint。 - 不要让 Codex 长时间保持开启状态,定期重启能强制 SQLite 完成 checkpoint。
- 如果使用 DeepSeek 等第三方 API,注意日志记录更频繁,WAL 膨胀速度会比官方 API 更快,需要更频繁的维护。
总结
SQLite WAL 模式本该提升并发性能,但 Codex 高频写入的场景下反而成了性能瓶颈。通过定期 checkpoint 和日志级别控制,能把加载速度稳定在百毫秒级别,避免再次卡死。