SQLite insert speed slows as number of records increases due to an index
众所周知,需要对sqlite进行微调,以达到50k个插入/秒的插入速度。这里有许多关于插入速度慢以及大量建议和基准的问题。
也有人声称,sqlite可以处理大量数据,50+GB的报告不会对正确的设置造成任何问题。
为了达到这些速度,我遵循了这里和其他地方的建议,我对35K-45K插入/秒很满意。我遇到的问题是,所有的基准测试都只显示插入速度快且记录小于1米。我看到的是插入速度似乎与表的大小成反比。
问题我的用例需要在一个链接表中存储500m到1b个元组(
前10M行的性能非常好,~35K个插入/s,但到表有~20M行时,性能开始下降。我现在看到大约100个插入/秒。
桌子的大小不是特别大。有20米的行,磁盘上的大小约为500兆字节。
这个项目是用Perl编写的。
问题这是sqlite中大型表的现实情况,还是有什么秘密可以为行数大于10米的表保持较高的插入率?
如果可能,我想避免的已知解决方法- 删除索引,添加记录,然后重新索引:这是一个很好的解决方法,但是当数据库在更新过程中仍然需要可用时不起作用。使数据库在X分钟/天内完全不可访问是行不通的。
- 将表分成更小的子表/文件:这在短期内有效,我已经对此进行了试验。问题是,当查询时,我需要能够从整个历史记录中检索数据,这意味着最终我将达到62个表的附件限制。在一个临时表中附加、收集结果,以及每个请求分离数百次似乎是一项繁重的工作和开销,但是如果没有其他选择,我将尝试它。
- 设置:我不知道C(?!)所以我不想为了完成这件事而学习它。不过,我看不出使用Perl设置这个参数的任何方法。
更新
按照蒂姆的建议,一个指数正在导致尽管sqlite声称它具有在处理大型数据集时,我对以下内容进行了基准比较设置:
- 插入行:1400万
- 提交批大小:50000条记录
cache_size 杂注:10000page_size 杂注:4096temp_store 杂注:内存journal_mode 杂注:删除synchronous 杂注:关
在我的项目中,和下面的基准测试结果一样,创建了一个基于文件的临时表,并且SQLite的内置支持用于导入csv数据。然后附加临时表在接收数据库中插入50000行集合
显然,索引会导致插入速度随着表大小的增加而减慢。
从上面的数据可以很清楚地看出,正确的答案可以分配给Tim的答案,而不是断言sqlite不能处理它。显然,如果索引数据集不是用例的一部分,它可以处理大型数据集。我使用sqlite只是为了这个目的,作为日志系统的后端,有一段时间了,它不需要索引,所以我对我所经历的放缓感到非常惊讶。
结论如果有人发现自己想要使用sqlite存储大量数据并对其进行索引,那么使用shard可能是解决方法。我最终决定使用MD5哈希的前三个字符(
如果您的要求是找到一个特定的z_id和与之链接的x_id和y_id(不同于快速选择z_id的范围),您可以查看一个无索引哈希表嵌套的关系数据库,该数据库允许您立即找到一个特定z_id的方法,以便获得其y_id和x_id——而不需要索引开销和t随着索引的增长,插入时的性能也随之下降。为了避免聚集,也就是说桶碰撞,选择一个关键哈希算法,将最大的权重放在具有最大变化(右加权)的z_id的数字上。
P.S.例如,使用B树的数据库最初可能比使用线性散列的数据库看起来更快,但随着B树性能开始下降,插入性能将与线性散列保持水平。
P.P.S.回答Kawing Chiu的问题:与此相关的核心特性是,这样的数据库依赖所谓的"稀疏"表,其中记录的物理位置由一个哈希算法确定,该算法将记录键作为输入。这种方法允许直接搜索记录在表中的位置,而不需要索引的中介。由于不需要遍历索引或重新平衡索引,因此插入时间保持不变,因为表的填充更加密集。相比之下,对于B树,插入时间随着索引树的增长而降低。具有大量并发插入的OLTP应用程序可以从这种稀疏表方法中获益。这些记录散布在整个桌子上。分散在稀疏表的"苔原"上的记录的缺点是,收集具有共同值的大型记录集(如邮政编码)可能会比较慢。哈希稀疏表方法被优化为插入和检索单个记录,以及检索相关记录的网络,而不是具有共同字段值的大型记录集。
嵌套的关系数据库允许行的列中有元组。
很好的问题和非常有趣的后续行动!
我只想简单地说一句:您提到过,将表拆分为较小的子表/文件,稍后再附加它们不是一个选项,因为您将很快达到62个附加数据库的硬限制。虽然这是完全正确的,但我认为您没有考虑过中间的选择:将数据分为多个表,但继续使用相同的单个数据库(文件)。
我做了一个非常粗略的基准测试,只是为了确保我的建议确实会对绩效产生影响。
Schema:1 2 3 4 5 | CREATE TABLE IF NOT EXISTS"test_$i" ( "i" integer NOT NULL, "md5" text(32) NOT NULL ); |
数据-200万行:
i =1..2000000md5 =i 的md5十六进制摘要
每笔交易=50000
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | 0..50000 records inserted in 1.87 seconds 50000..100000 records inserted in 1.92 seconds 100000..150000 records inserted in 1.97 seconds 150000..200000 records inserted in 1.99 seconds 200000..250000 records inserted in 2.19 seconds 250000..300000 records inserted in 1.94 seconds 300000..350000 records inserted in 1.94 seconds 350000..400000 records inserted in 1.94 seconds 400000..450000 records inserted in 1.94 seconds 450000..500000 records inserted in 2.50 seconds 500000..550000 records inserted in 1.94 seconds 550000..600000 records inserted in 1.94 seconds 600000..650000 records inserted in 1.93 seconds 650000..700000 records inserted in 1.94 seconds 700000..750000 records inserted in 1.94 seconds 750000..800000 records inserted in 1.94 seconds 800000..850000 records inserted in 1.93 seconds 850000..900000 records inserted in 1.95 seconds 900000..950000 records inserted in 1.94 seconds 950000..1000000 records inserted in 1.94 seconds 1000000..1050000 records inserted in 1.95 seconds 1050000..1100000 records inserted in 1.95 seconds 1100000..1150000 records inserted in 1.95 seconds 1150000..1200000 records inserted in 1.95 seconds 1200000..1250000 records inserted in 1.96 seconds 1250000..1300000 records inserted in 1.98 seconds 1300000..1350000 records inserted in 1.95 seconds 1350000..1400000 records inserted in 1.95 seconds 1400000..1450000 records inserted in 1.95 seconds 1450000..1500000 records inserted in 1.95 seconds 1500000..1550000 records inserted in 1.95 seconds 1550000..1600000 records inserted in 1.95 seconds 1600000..1650000 records inserted in 1.95 seconds 1650000..1700000 records inserted in 1.96 seconds 1700000..1750000 records inserted in 1.95 seconds 1750000..1800000 records inserted in 1.95 seconds 1800000..1850000 records inserted in 1.94 seconds 1850000..1900000 records inserted in 1.95 seconds 1900000..1950000 records inserted in 1.95 seconds 1950000..2000000 records inserted in 1.95 seconds |
数据库文件大小:89.2 mib。
数据库:1;表:1;索引:1(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | 0..50000 records inserted in 2.90 seconds 50000..100000 records inserted in 11.64 seconds 100000..150000 records inserted in 10.85 seconds 150000..200000 records inserted in 10.62 seconds 200000..250000 records inserted in 11.28 seconds 250000..300000 records inserted in 12.09 seconds 300000..350000 records inserted in 10.60 seconds 350000..400000 records inserted in 12.25 seconds 400000..450000 records inserted in 13.83 seconds 450000..500000 records inserted in 14.48 seconds 500000..550000 records inserted in 11.08 seconds 550000..600000 records inserted in 10.72 seconds 600000..650000 records inserted in 14.99 seconds 650000..700000 records inserted in 10.85 seconds 700000..750000 records inserted in 11.25 seconds 750000..800000 records inserted in 17.68 seconds 800000..850000 records inserted in 14.44 seconds 850000..900000 records inserted in 19.46 seconds 900000..950000 records inserted in 16.41 seconds 950000..1000000 records inserted in 22.41 seconds 1000000..1050000 records inserted in 24.68 seconds 1050000..1100000 records inserted in 28.12 seconds 1100000..1150000 records inserted in 26.85 seconds 1150000..1200000 records inserted in 28.57 seconds 1200000..1250000 records inserted in 29.17 seconds 1250000..1300000 records inserted in 36.99 seconds 1300000..1350000 records inserted in 30.66 seconds 1350000..1400000 records inserted in 32.06 seconds 1400000..1450000 records inserted in 33.14 seconds 1450000..1500000 records inserted in 47.74 seconds 1500000..1550000 records inserted in 34.51 seconds 1550000..1600000 records inserted in 39.16 seconds 1600000..1650000 records inserted in 37.69 seconds 1650000..1700000 records inserted in 37.82 seconds 1700000..1750000 records inserted in 41.43 seconds 1750000..1800000 records inserted in 49.58 seconds 1800000..1850000 records inserted in 44.08 seconds 1850000..1900000 records inserted in 57.17 seconds 1900000..1950000 records inserted in 50.04 seconds 1950000..2000000 records inserted in 42.15 seconds |
数据库文件大小:181.1 mib。
数据库:1;表:20(每100000条记录一个);索引:1(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | 0..50000 records inserted in 2.91 seconds 50000..100000 records inserted in 10.30 seconds 100000..150000 records inserted in 10.85 seconds 150000..200000 records inserted in 10.45 seconds 200000..250000 records inserted in 10.11 seconds 250000..300000 records inserted in 11.04 seconds 300000..350000 records inserted in 10.25 seconds 350000..400000 records inserted in 10.36 seconds 400000..450000 records inserted in 11.48 seconds 450000..500000 records inserted in 10.97 seconds 500000..550000 records inserted in 10.86 seconds 550000..600000 records inserted in 10.35 seconds 600000..650000 records inserted in 10.77 seconds 650000..700000 records inserted in 10.62 seconds 700000..750000 records inserted in 10.57 seconds 750000..800000 records inserted in 11.13 seconds 800000..850000 records inserted in 10.44 seconds 850000..900000 records inserted in 10.40 seconds 900000..950000 records inserted in 10.70 seconds 950000..1000000 records inserted in 10.53 seconds 1000000..1050000 records inserted in 10.98 seconds 1050000..1100000 records inserted in 11.56 seconds 1100000..1150000 records inserted in 10.66 seconds 1150000..1200000 records inserted in 10.38 seconds 1200000..1250000 records inserted in 10.24 seconds 1250000..1300000 records inserted in 10.80 seconds 1300000..1350000 records inserted in 10.85 seconds 1350000..1400000 records inserted in 10.46 seconds 1400000..1450000 records inserted in 10.25 seconds 1450000..1500000 records inserted in 10.98 seconds 1500000..1550000 records inserted in 10.15 seconds 1550000..1600000 records inserted in 11.81 seconds 1600000..1650000 records inserted in 10.80 seconds 1650000..1700000 records inserted in 11.06 seconds 1700000..1750000 records inserted in 10.24 seconds 1750000..1800000 records inserted in 10.57 seconds 1800000..1850000 records inserted in 11.54 seconds 1850000..1900000 records inserted in 10.80 seconds 1900000..1950000 records inserted in 11.07 seconds 1950000..2000000 records inserted in 13.27 seconds |
数据库文件大小:180.1 mib。
如您所见,如果将数据分为多个表,插入速度将保持几乎不变。
不幸的是,我认为这是SQLite中大型表的一个限制。它不是为在大规模或大容量数据集上运行而设计的。虽然我知道这可能会大大增加项目的复杂性,但您最好还是研究更复杂的数据库解决方案,以满足您的需要。
从您链接的所有内容来看,表大小与访问速度之间的关系似乎是一种直接权衡。不能两者兼得。
在我的项目中,我无法共享数据库,因为它在不同的列上建立了索引。为了加快插入速度,我在/dev/shm(=linux ramdisk)上创建数据库,然后将其复制到本地磁盘。这显然只适用于一次写入、多次读取的数据库。
我怀疑索引的哈希值冲突会导致插入速度变慢。
当一个表中有许多行时,索引列哈希值冲突将更频繁地发生。这意味着SQLite引擎需要计算哈希值两次或三次,甚至可能四次,才能得到不同的哈希值。
所以我想这就是当表有很多行时,SQLite插入速度慢的根本原因。
这一点可以解释为什么使用碎片可以避免这个问题。谁是sqlite领域的真正专家来证实或否认我的观点?