注意不要直接只复制主库文件而忽略 WAL。使用 SQLite backup API 可以得到一致性备份,更适合数据库仍可能被进程打开的场景。
五、用 Trigger 拦截 logs 表写入
拦截方式很简单:在 logs 表上创建 BEFORE INSERT trigger,并使用 RAISE(IGNORE) 忽略插入。
1 2 3 4 5
CREATETRIGGER IF NOTEXISTS codex_block_logs_insert BEFORE INSERTON logs BEGIN SELECT RAISE(IGNORE); END;
这个 trigger 的效果是:
任何对 logs 表的新增写入都会被忽略。
不抛出错误,调用方通常不会因为 insert 失败而中断。
原有历史日志仍保留。
不影响其他 SQLite 表。
可以用 Python 执行:
1 2 3 4 5 6 7 8 9 10 11 12 13
python3 -c "import sqlite3, pathlib p = pathlib.Path.home() / '.codex' / 'logs_2.sqlite' con = sqlite3.connect(p, timeout=10) con.execute('PRAGMA busy_timeout=10000') con.execute(\"\"\" CREATE TRIGGER IF NOT EXISTS codex_block_logs_insert BEFORE INSERT ON logs BEGIN SELECT RAISE(IGNORE); END \"\"\") con.commit() con.close()"
创建后检查:
1 2 3 4
SELECT name, sql FROM sqlite_master WHERE type ='trigger' AND tbl_name ='logs';
应能看到:
1 2 3
codex_block_logs_insert BEFORE INSERT ON logs SELECT RAISE(IGNORE)
六、Checkpoint 并截断 WAL
trigger 生效后,需要把 WAL 处理掉:
1
PRAGMA wal_checkpoint(TRUNCATE);
Python 执行方式:
1 2 3 4 5
python3 -c "import sqlite3, pathlib p = pathlib.Path.home() / '.codex' / 'logs_2.sqlite' con = sqlite3.connect(p, timeout=10) print(con.execute('PRAGMA wal_checkpoint(TRUNCATE)').fetchall()) con.close()"
本次返回:
1
[(0, 0, 0)]
随后查看 WAL:
1
stat -c '%n %s' ~/.codex/logs_2.sqlite-wal
结果:
1
wal_size=0
七、采样确认不再增长
最后要做的是采样,而不是只看一次。
采样脚本:
1 2 3 4 5 6 7 8 9 10
python3 -c "import sqlite3, pathlib, time p = pathlib.Path.home() / '.codex' / 'logs_2.sqlite' wal = p.with_name(p.name + '-wal') for i in range(6): con = sqlite3.connect(p, timeout=10) row = con.execute('SELECT MAX(id), COUNT(*) FROM logs').fetchone() con.close() wal_size = wal.stat().st_size if wal.exists() else 0 print(f'sample={i} max_id={row[0]} count={row[1]} wal_size={wal_size}') time.sleep(3)"