Tag: 优化

提高SQLite的每秒插入性能?

优化SQLite是非常棘手的。C应用程序的批量插入性能可以从每秒85次插入到每秒超过96,000次插入! 背景:我们使用SQLite作为桌面应用程序的一部分。我们有大量的配置数据存储在XML文件中,这些数据被解析并加载到SQLite数据库中,以便在初始化应用程序时进一步处理。SQLite非常适合这种情况,因为它速度很快,不需要专门的配置,数据库作为单个文件存储在磁盘上。 理由: 最初我对我所看到的表现感到失望。事实证明,根据数据库的配置方式以及如何使用API​​,SQLite的性能可能会有很大差异(对于批量插入和选择)。找出所有的选项和技术并不是一件简单的事情,所以我认为创建这个社区wiki条目与Stack Overflow读者分享结果是很明智的,以便为其他人省去相同调查的麻烦。 实验:我认为最好是编写一些C代码并实际测量各种选项的影响,而不是简单地谈论一般意义上的性能提示(即“使用事务!”)。我们将从一些简单的数据开始: 多伦多市全部交通时间表的28 MB TAB分隔文本文件(约865,000条记录) 我的测试机是运行Windows XP的3.60 GHz P4。 代码使用Visual C ++ 2005作为“发布”进行编译,使用“完全优化”(/ Ox)和优先快速代码(/ Ot)。 我使用SQLite“Amalgamation”,直接编译到我的测试应用程序中。我碰巧遇到的SQLite版本有点旧(3.6.7),但我怀疑这些结果会与最新版本相媲美(如果您不这么认为,请留下评论)。 我们来写一些代码吧! 代码:一个简单的C程序,逐行读取文本文件,将字符串拆分为值,然后将数据插入到SQLite数据库中。在这个“基准”版本的代码中,数据库被创建,但我们不会实际插入数据: /************************************************************* Baseline code to experiment with SQLite performance. Input data is a 28 MB TAB-delimited text file of the complete Toronto Transit System schedule/route info from http://www.toronto.ca/open/datasets/ttc-routes/ **************************************************************/ #include <stdio.h> #include <stdlib.h> #include <time.h> #include

为什么处理排序后的数组比未排序的数组更快?

这是一个C ++代码,看起来很奇特。出于一些奇怪的原因,对数据进行排序后使得代码神奇地快了近6倍。 没有std::sort(data, data + arraySize);,代码运行在11.54秒。 使用排序后的数据,代码在1.93秒内运行。 起初,我认为这可能只是一种语言或编译器异常。所以我尝试了Java。 有点类似但不太极端的结果。 我的第一个想法是,排序将数据带入缓存,但后来我觉得是多么愚蠢的,因为该数组刚刚生成。 到底是怎么回事? 为什么处理排序后的数组比未排序的数组更快? 代码正在总结一些独立的术语,顺序应该不重要。 问题评论 只是为了记录。在Windows / VS2017 / i7-6700K 4GHz两个版本之间没有区别。这两种情况都需要0.6s。如果外部循环的迭代次数增加了10倍,执行时间也增加了10倍,至6s。 任何使用一个cmov或其他无分支实现(如自动矢量化pcmpgtd)的编译器将具有不依赖于任何CPU的数据的性能。但是,如果它是分支的,它将依赖于任何具有无序推测执行的CPU的排序。(即使是高性能的有序CPU使用分支预测来避免在采取的分支上获取/解码泡泡;缺失惩罚更小)。 @KyleMit和它们有什么关系?我还没有读太多 @mohitmun,这两个安全漏洞都属于被分类为“分支目标注入”攻击的一大类漏洞   答案:   你是分支预测失败的受害者。 什么是分支预测? 考虑一个铁路交界处: 现在为了争论,假设这是在19世纪 – 在长距离或无线电通信之前。 你是一个路口的运营商,你听到一辆火车来了。你不知道应该走哪条路。你停下火车去询问司机他们想要的方向。然后你适当地设置开关。 火车很重,有很多的惯性。所以他们永远都要开始放慢速度。 有没有更好的办法?你猜猜火车会去哪个方向! 如果你猜对了,它会继续。 如果你猜错了,那么队长会停下来,然后向你大喊,打开开关。然后它可以重新启动其他路径。 如果你猜对了,火车永远不会停下来。 如果您经常猜错,火车会花费大量时间停止,备份和重新启动。   考虑一个if语句:在处理器级别,它是一个分支指令: 你是一个处理器,你看到一个分支。你不知道它会走哪条路。你是做什么?您停止执行并等到前面的指示完成。然后你继续正确的道路。 现代处理器复杂,流水线长。所以他们永远要“热身”,“放慢速度”。 有没有更好的办法?你猜猜分支会走哪个方向! 如果你猜对了,你继续执行。 如果你猜错了,你需要刷新管道并回滚到分支。然后你可以重新开始下另一个路径。 如果你每次都猜对了,执行永远不会停止。 如果你经常猜错,你会花费很多时间拖延,回滚,然后重新开始。 这是分支预测。我承认这不是最好的比喻,因为火车可以用一面旗子标出方向。但在计算机中,处理器不知道分支将走向哪个方向,直到最后一刻。 那么你怎么会战略性地猜测,以尽量减少火车必须备份和走下另一条路的次数呢?你看过去的历史!如果火车剩下99%的时间,那么你猜就走了。如果它交替,那么你交替你的猜测。如果每三次都有一种方法,你猜也一样。 换句话说,你试图找出一个模式并遵循它。这或多或少是分支预测器的工作原理。 大多数应用程序都有良好的分支。所以现代分支预测器通常会达到> 90%的命中率。但是当面对不可预知的分支而没有可识别的模式时,分支预测器实际上是无用的。 进一步阅读:维基百科的“分支预测”文章。 正如上文所暗示的,罪魁祸首是这个陈述: