Writing records in SQLITE database taking huge time. How to improve efficiency of insert operation?
在数据库表中插入大约1亿1000万条记录,使用C++接口API占用了大量的时间(>1小时)。
有没有办法减少这一时间,提高插入操作的效率?
我在一个事务中对1000条记录进行分组,然后执行它们。
sqlite3_exec(begin transaction);
sqlite3_exec(<1000> insertions);
sqlite3_exec(end transaction);
这需要花费大量时间。
如何提高插入效率?
假设您的所有语句都是同一个表中的INSERT,那么您可能能够通过将该语句创建为准备好的语句来提高性能,然后对每一行重用它(每次都将其绑定到新数据)。这里是对准备好的语句的一些解释;其基本思想是,不要使用sqlite3_exec,而是使用sqlite3_prepare_v2准备一个语句(使用占位符而不是数据),然后针对每一行将其绑定到数据,执行并重置它。这样,sqlite就不必每次都重新分析/重新编译语句,因为只有值会更改。
- sqlite3_exec已经做了准备,即每1000次插入就有一次准备。这可以得到改善,但它可能会将吞吐量提高不到1%。
- @这正是这个答案的关键所在。您不必为每个sqlite3_exec做准备,而是为整个批次做一个单独的准备。这种技术可以节省多少时间只能通过测量来确定,而没有必要去猜测性能改进的"可能"是什么。
- @ AlgirdasPreid?IUS衡量是很好的,但经验和猜测是不同的问题。例如,我的close as-duplicate建议在使用一个准备好的语句时将插入吞吐量增加了一倍以上,但这与对sqlite3_exec的单次插入调用相比。假设成本是加性的,那么这里的预期收益仅为约0.13%。因此,我考虑显式准备微优化。关联结果表明,减少交易数量是1优先事项。
- @Arnevogel我对这个问题的初步理解是,操作人员在每笔交易中向sqlite3_exec打了1000个电话。可能他们只做了一个,有很多值元组,但是在这种情况下,解析/编译语句的成本会相应地更高。
- @Arnevogel"在哪里使用一个准备好的语句将插入吞吐量增加了一倍以上?"?将sqlite3_exec用于单行时"每秒插入85次",而使用准备好的语句时"每秒插入53000次",这是改进的600倍。将双重改进与将全部插入放入事务中进行比较。这不是所示代码中所做的。
- @sneftel i假定,用于批量操作的sqlite3_exec的预期用途是具有占位符和提供回调的值。但是,在再次阅读文档时,我看到回调只用于处理输出,而不是输入。我不应该假设C接口比实际的更有用。因此,我收回了使用显式准备是一种微观优化的说法。
- @ AlgirdasPreid?US85每秒的操作是针对"最坏情况"的,其中每个插入都在一个单独的事务中。单笔交易,但每行一个sqlite3_exec是23000个操作。单笔交易,单笔准备为53000个操作。OP每1000行执行一个事务,这可能不是最佳的,但与"最坏情况"非常不同。
- @斯奈费尔,谢谢。它解决了我的问题,插入速度很快。