sqlite3_wal_checkpoint_v2始终返回SQL_BUSY

sqlite3_wal_checkpoint_v2 always returns SQL_BUSY

本文关键字:返回 SQL BUSY v2 wal checkpoint sqlite3      更新时间:2023-10-16

上下文

我在Windows C++程序中使用sqlite 3.7.7.1版本,我正在创建一个只有一个与sqlite_OPEN_READWRITE|sqlite_OPEN_CREATE|sqlite_OPEN_NOMUTEX连接的数据库。

我使用SQLite是因为我需要非常快速的ACID事务。数据库存储在Windows XP sp3上的NTFS固态驱动器上。

这个数据库有3个表,每个事务包含3个表。最大的事务在其中一个表中插入12行,在另一个表插入1行,并更新第三个表。

我的应用程序有一个400ms的周期,数据库用于在每个周期开始时发生的9个事务。我知道我的平均事务需要15毫秒(60毫秒是非常罕见的峰值(大约60万个事务中有1个在Windows FlushFileBuffers函数中浪费了时间(,所以数据库只用于400毫秒周期的前150毫秒。

基准测试之后,WAL日志为我的应用程序提供了最佳性能。

但是,我对WAL日志有一个问题:xxx-WAL文件正在不停地增长(在500k事务之后,WAL文件为8GB!(。激活auto_checkpoint没有帮助。

当试图通过使用SQLITE_checkpoint_RESTART选项调用sqlite3_wal_checkpoint_v2手动执行检查点时,sqlite3一直返回SQLITE_LOCKED。

我发现,当我使用sqlite3_exec创建一个表时,连接将永远锁定怎么解释?有办法避免这种情况吗

因此,关闭连接并重新打开它,我尝试调用sqlite3_wal_checkpoint_v2,但这次它返回了SQLITE_BUSY。即使我用1秒调用sqlite3_busy_timeout,它仍然返回SQLITE_busy。

问题

知道数据库上只使用了一个连接,这个连接由几个线程使用,但通过我的应用程序端的互斥体序列化,是什么导致数据库繁忙

更多信息:

  • 我使用了几个准备好的语句,这些语句是我在整个周期中保存的(甚至有一个用于TRANSACTION BEGIN和TRANSACTION COMMIT(
  • 提交第一个事务后,DB似乎很忙

尽管我在sqlite网站上阅读过,但我很难理解sqlite的锁定和繁忙方案。有人在这方面有好的链接吗?

我找到了问题的原因,这是我这边的两件愚蠢的事情:

用"PRAGMA page_size"查询页面大小时,我只是在读取行,而不是用"sqlite3_reset"或sqlite3_finalize重置或完成语句(它被我测试的C++包装程序隐藏了(。

这导致数据库被锁定。然后,我在关闭数据库之前没有完成这个查询,这导致数据库在重新打开后返回繁忙状态