SQLite:实际限制是什么?

15
在你将这个问题标记为重复之前,请听我说! 我已经阅读了这里关于如何提高性能的问题,例如仅举几个例子Improve INSERT-per-second performance of SQLite?What are the performance characteristics of sqlite with very large database files? 我正在努力让sqlite与5 GB大小的数据库文件一起工作。 相反,有些人声称,即使数据库大小为160 GB,sqlite也可以“很好地”工作。 我自己还没有尝试过,但从所提出的问题来看,我猜所有基准测试可能只是在数据库中的一个表中完成。
我正在使用具有以下特点的数据库: - 大约20个表 - 其中有一半以上的表具有15列以上 - 这些15列左右的表中的每个都有6/7个外键列 - 其中一些表已经增长到拥有2700万条记录,时间不到一个月
我使用的开发机器是3 GHz四核机器,带有4 GB的RAM,但是仍然需要超过3分钟才能查询这些大表中的行数。
我找不到任何水平分区数据的方法。 我最好的办法是将数据分割成多个数据库文件,每个表一个文件。 但是,在这种情况下,据我所知,无法使用外键列约束,因此我必须创建一个自给自足的表(没有任何外键)。
所以我的问题是: a)我是否在错误的数据库中工作? b)你认为我在哪里出错了? c)我尚未在外键上添加索引,但如果仅查询行数需要四分钟,外键索引如何帮助我?
编辑 提供更多信息即使没有人要求 :)我正在使用SQLite 3.7.9版本和system.data.sqlite.dll 1.0.77.0版本 编辑2: 我认为与160GB的人不同的是,他们可能会选择一个单独的记录或一小段记录。但我必须加载表中的全部2700万行数据,并将它们与另一个表连接,按用户要求分组记录并返回结果。请提供任何关于如何最优化数据库以实现此类结果的建议。
在我的情况下,无法缓存先前查询的结果,因为这没有意义。命中缓存的几率相当低。


2
如果其他人说160GB的数据库运行良好,显然这一定是你在做某些事情,但你没有告诉我们*你是如何做到的,除了说你没有为外键建立索引。您是否尝试过索引外键? - Lasse V. Karlsen
根据提出的问题,我猜测160 Gb的数据库只使用了一个表。 不,我还没有在外键上添加索引,因为即使我运行一个不涉及外键的查询,比如'Select count(*) from some_table',sqlite也需要几分钟才能返回结果。 我会在外键上添加索引并回来再试。 请告诉我您还想知道什么信息。 - WPFAbsoluteNewBie
你的表上有索引吗? - Lasse V. Karlsen
@Nick Dandoulakis:我注意到我的进程有太多的页面错误,尽管我的进程的内存使用并不高,并且根据任务管理器的显示,我仍然有大约1GB的可用内存。 - WPFAbsoluteNewBie
https://dev59.com/wWYq5IYBdhLWcg3weQgy | https://dev59.com/8nE85IYBdhLWcg3wbS_1 - Ciro Santilli OurBigBook.com
显示剩余4条评论
3个回答

6
这里需要考虑很多因素,但我首先的建议是不要一味地相信他人的性能统计数据。数据库性能取决于很多事情,包括数据库的结构、查询的复杂程度、定义(或未定义)哪些索引,以及通常只是其中保存的数据量的大小。很多报告的性能数字都来源于反复试验,或将数据库与手头工作匹配起来。换句话说,除非你的数据集和结构几乎完全相同,否则从任何数据库管理系统中获得的性能都不能简单地与其他应用程序的性能进行比较-它们肯定是一种指导,并且可能是努力追求的目标,但你并不一定会从中获得疯狂的性能“开箱即用”。
作为起点,我建议开始对那些真正大型表上的数据创建索引(从评论中看起来你已经这样做了),然后观察结果。尽管计算四分钟是相当长的时间,但不要就此停止。添加一些索引,更改它们的定义方式,问问自己是否存储了不必要的数据,并查看其他数据库查询,而不仅仅是计数查询,以评估性能。寻找使用SQLite处理大量行的其他应用程序和博客文章,看看它们为解决此问题所做的工作(其中可能包括更改数据库)。基本上,尝试一些东西-然后进行判断。不要让最初的恐惧阻止你,认为自己走了弯路。也许你是,也许你不是,但不要仅止于"COUNT"查询。无论如何,一个表中拥有2700万条记录是非常多的。
最后,一个具体的建议是:在SQLite中,不要将数据库拆分为多个文件-我认为这样做没有帮助,因为那样你将不得不进行大量额外的查询工作,然后在从多个查询返回结果后手动连接你的各个表。这是重新发明关系型数据库管理系统对你所做的事情,是一个疯狂的想法。你不会以某种方式比RDBMS系统的创建者更快地完成联接-在那里肯定会浪费时间。

请问您可以解释一下“切割表”是什么意思吗?据我所知,sqlite并不本身支持任何水平分区。 - WPFAbsoluteNewBie
我并不是在指数据库,那只是个说法。当我说“无论你怎么切入(解决这个问题)……”时,我只是想表达“无论你怎么着手解决这个问题,在一个表中有2700万条记录确实很多。” - jefflunt

1
在SQLite中,使用select count(*)进行比较时速度总是比其他DMBS慢,因为它会对该特定请求进行表扫描。它没有统计表来帮助查询。但这并不意味着你的应用程序查询会很慢。你需要测试你的查询以了解真正的期望结果。
一些通用准则:索引是绝对必须的,因为在涉及巨大数据量时,通过二叉树导航数据子集要比遍历整个表快得多。为了帮助加载时间,你应该为唯一索引排序你的数据,如果你没有唯一索引,则为最大索引。如果你可以在加载之前删除索引,然后在加载后重新添加,那么速度会更快。如果这些技术不能满足你的操作和SLA参数,那么就是做水平分区的时候了,并使用“attach”跨越你需要的数据范围。SQLite可以支持最多10个附件。我知道有些人说分区是工具的工作,而不是开发人员的工作,但当你面临物理限制时,你必须卷起袖子,或者选择一个商业工具,在你的工作下为你完成它。

-1
如果您在客户端直接部署了50MB或更多的数据库,则意味着您做错了什么。 尝试迁移到服务器端,同时在客户端存储关键重要值(只是引用)。 您将没有实时性,但至少会产生一个适当的解决方案。 “服务器端”是对您的问题的答案,也就是说,如果您放弃或优化实时要求,因为这是您拥有的东西(根据您的描述)。 在任何情况下,SQLite几乎可以处理任何内容,但基于个人经验,尽可能保持简单,即使以实时结果为代价。

2
并非所有情况都适用于同一种解决方案。在许多场景中,使用大型客户端数据库是完全合理的。 - David Stein

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接