我正在开发一个用 C 编写的项目,该项目会生成近 350k 序列以保存在 sqlite 数据库中。对于每个序列,我必须在表中插入(或忽略)一个字符串并更新其他表中的一行。
我尝试了这个“指南”,但每秒无法达到超过 30k 的操作。
我正在使用每个 1M 操作的事务(插入和更新)和 PRAGMA 同步 = OFF
我有什么选择来解决这个瓶颈?
实际上,SQLite 在普通台式计算机上每秒可以轻松执行 50,000 或更多的 INSERT 语句。但它每秒只会进行几十次交易。交易速度受磁盘驱动器转速的限制。一个事务通常需要磁盘盘片完全旋转两次,这在 7200RPM 磁盘驱动器上将您限制为每秒大约 60 个事务。
事务速度受到磁盘驱动器速度的限制,因为(默认情况下)SQLite 实际上会等到数据真正安全地存储在磁盘表面上之后才会完成事务。这样,如果您突然断电或操作系统崩溃,您的数据仍然是安全的。有关详细信息,请阅读 SQLite 中的原子提交。
默认情况下,每个 INSERT 语句都是它自己的事务。但是,如果您使用 BEGIN...COMMIT 包围多个 INSERT 语句,则所有插入都将分组到一个事务中。提交事务所需的时间在所有封闭的插入语句中分摊,因此每个插入语句的时间大大减少。
另一种选择是运行 PRAGMA synchronous=OFF。此命令将导致 SQLite 不等待数据到达磁盘表面,这将使写入操作看起来要快得多。但是,如果您在事务处理过程中断电,您的数据库文件可能会损坏。
请查看此常见问题解答,它解释了插入瓶颈问题等。
我通过简化查询提高了数据库的性能。
最初,我对应该添加到表中的每个元素都有一个 INSERT + UPDATE。通过简化,我创建了另一个表,一个临时表,对列没有任何约束,只需在其上插入数据。最后我使用:
CREATE TABLE my_table AS SELECT ... FROM my_tmp_table ... GROUP BY something
并使用我需要的所有约束创建我的最终表。
现在它达到了我需要的性能。