SQLite WAL模式,后台线程检查点,wal日志永不收缩
SQLite的文档提到(在这里)你可以通过在一个单独的线程上运行检查点来避免WAL模式下的暂停。我试过这样做,但似乎没有效果:'-wal
'文件不断增大,不清楚是否有数据真的被复制回主数据库文件中,最重要的是,当'-wal
'文件变得足够大(超过一GB)时,主线程开始需要等待检查点的完成。
在我的应用中,主线程不断做一些类似于下面的事情,其中generate_data
会生成大约一百万行要插入的数据:
db = sqlite3.connect("database.db")
cursor = db.cursor()
cursor.execute("PRAGMA wal_autocheckpoint = 0")
for datum in generate_data():
# It is a damned shame that there is no way to do this in one operation.
cursor.execute("SELECT id FROM strings WHERE str = ?", (datum.text,))
row = cursor.fetchone()
if row is not None:
id = row[0]
else:
cur.execute("INSERT INTO strings VALUES(NULL, ?)", (datum.text,))
id = cur.lastrowid
cursor.execute("INSERT INTO data VALUES (?, ?, ?)",
(id, datum.foo, datum.bar))
batch_size += 1
if batch_size > batch_limit:
db.commit()
batch_size = 0
而检查点线程则执行以下操作:
db = sqlite3.connect("database.db")
cursor = db.cursor()
cursor.execute("PRAGMA wal_autocheckpoint = 0")
while True:
time.sleep(10)
cursor.execute("PRAGMA wal_checkpoint(PASSIVE)")
(由于它们在不同的线程中,所以必须使用不同的数据库连接,因为pysqlite不支持多个线程共享一个连接。)切换到FULL或RESTART检查点并没有帮助——这样检查点就会失败。
我该如何让这个真正有效呢?我希望的结果是:1)主线程永远不需要等待,2)日志文件不会无限增长。
1 个回答
5
检查点操作需要锁住整个数据库,这样其他的读写操作就都得被阻止了。
(如果是被动的检查点操作,那就直接中止了。)
所以在一个单独的线程中运行检查点操作并不会提高并发性。
(SQLite的文档之所以这么说,是因为主线程可能没有设计成在空闲时处理检查点操作。)
如果你一直在访问数据库,就无法进行检查点操作。
如果你的批量操作让WAL文件变得太大,你应该在这个循环中插入明确的检查点(或者依赖自动检查点功能)。