如何使用多个 INNER JOIN 加快查询速度
Posted
技术标签:
【中文标题】如何使用多个 INNER JOIN 加快查询速度【英文标题】:How to speed up query with multiple INNER JOINs 【发布时间】:2009-10-13 16:15:52 【问题描述】:为了满足我的简单数据库需求,我一直在尝试从 ms-access 文件切换到 SQLite 文件;出于通常的原因:较小的文件大小、较少的开销、开源等。
阻止我进行切换的一件事是 SQLite 似乎缺乏速度。对于简单的 SELECT 查询,SQLite 的性能似乎与 MS-Access 一样好,甚至更好。带有多个 INNER JOIN 语句的相当复杂的 SELECT 查询会出现问题:
SELECT DISTINCT
DESCRIPTIONS.[oCode] AS OptionCode,
DESCRIPTIONS.[descShort] AS OptionDescription
FROM DESCRIPTIONS
INNER JOIN tbl_D_E ON DESCRIPTIONS.[oCode] = tbl_D_E.[D]
INNER JOIN tbl_D_F ON DESCRIPTIONS.[oCode] = tbl_D_F.[D]
INNER JOIN tbl_D_H ON DESCRIPTIONS.[oCode] = tbl_D_H.[D]
INNER JOIN tbl_D_J ON DESCRIPTIONS.[oCode] = tbl_D_J.[D]
INNER JOIN tbl_D_T ON DESCRIPTIONS.[oCode] = tbl_D_T.[D]
INNER JOIN tbl_Y_D ON DESCRIPTIONS.[oCode] = tbl_Y_D.[D]
WHERE ((tbl_D_E.[E] LIKE '%')
AND (tbl_D_H.[oType] ='STANDARD')
AND (tbl_D_J.[oType] ='STANDARD')
AND (tbl_Y_D.[Y] = '41')
AND (tbl_Y_D.[oType] ='STANDARD')
AND (DESCRIPTIONS.[oMod]='D'))
在 MS-Access 中,此查询在大约 2.5 秒内执行。在 SQLite 中,这需要 8 多点 分钟。无论我是从 VB 代码还是使用 sqlite3.exe 从命令提示符运行查询,都需要相同的时间。
所以我的问题如下:
-
SQLite 是否没有针对处理多个 INNER JOIN 语句进行优化?
我是否在查询中做了一些明显愚蠢的事情(因为我是 SQLite 的新手),这使得它变得如此缓慢?
并且在有人提出完全不同的技术之前,不,我不能切换。我的选择是 MS-Access 或 SQLite。 :)
更新: 为 SQLite 数据库中的每个列分配一个 INDEX 将查询时间从 8 多分钟减少到大约 6 秒。感谢Larry Lustig 解释了为什么需要索引。
【问题讨论】:
@Phill Pafford:我没有在 MS-Access 或 SQLite 数据上使用索引。我正在尝试比较对 sqlite 的访问,因此我在两者中都保留了相同的数据结构。 无法发布答案,因此尝试发表评论:MS Access 非常积极地代表您对列进行索引,而 SQLite 将要求您明确创建所需的索引。因此,Access 可能已为您编制了 [Description] 或 [D] 索引,但 SQLite 中缺少这些索引。我对 SQLite 中的大量 JOIN 活动没有经验。我在一个数据量比较少的Django项目中使用过,没有发现任何性能问题。 使用索引。 Access中有索引吗?如果不是,我仍然认为这是一个公平的比较,并且仍然认为它在两者中是相同的数据结构。反之,比较这两种产品同时削弱一种产品有什么好处? @Larry Lustig:感谢您提供的信息。我将尝试向 SQLite 数据添加索引,看看我得到了什么样的改进。 Larry 是对的,如果您在表之间实现参照完整性,Jet/ACE 会在连接的外键端创建隐藏索引。我认为他非常机敏地立即将此视为性能差异的可能原因。 【参考方案1】:根据要求,我将我之前的评论重新发布为实际答案(当我第一次发布评论时,由于某种原因,我无法将其发布为答案):
MS Access 非常积极地代表您对列进行索引,而 SQLite 将要求您显式创建所需的索引。因此,Access 可能为您编制了 [Description] 或 [D] 索引,但 SQLite 中缺少这些索引。我对 SQLite 中的大量 JOIN 活动没有经验。我在一个数据量比较少的 Django 项目中使用它,并没有发现任何性能问题。
【讨论】:
【参考方案2】:您对参考完整性有疑问吗?我问是因为有印象您有不必要的连接,所以我将您的查询重写为:
SELECT DISTINCT
t.[oCode] AS OptionCode,
t.[descShort] AS OptionDescription
FROM DESCRIPTIONS t
JOIN tbl_D_H h ON h.[D] = t.[oCode]
AND h.[oType] = 'STANDARD'
JOIN tbl_D_J j ON j.[D] = t.[oCode]
AND j.[oType] = 'STANDARD'
JOIN tbl_Y_D d ON d.[D] = t.[oCode]
AND d.[Y] = '41'
AND d.[oType] ='STANDARD'
WHERE t.[oMod] = 'D'
【讨论】:
@rexem:感谢您清理后的查询版本。我回去查看我的查询,结果发现我遗漏了几个 WHERE 语句,所以是的,我确实需要所有的 JOIN。我仍然从您的回答中学到了一些有用的东西。谢谢! Stewbob - 如果这确实是答案,您应该将其标记为这样,以便 rexem 获得积分。他做了一些出色的工作来提供这个解决方案! @Mark:根据 cmets 的说法,Larry Lustig 提供了答案,但没有回来发布它作为获得信用的答案。【参考方案3】:如果DESCRIPTIONS和tbl_D_E有多个行扫描,那么oCode和D应该被索引。看看这里的例子,看看如何索引和告诉有多少行扫描(http://www.siteconsortium.com/h/p1.php?id=mysql002)。
这可能会解决它..
使用 BTREE 在描述(oCode)上创建索引 ocode_index; CREATE INDEX d_index ON tbl_D_E (D) USING BTREE;
等等……
正确索引是一个难题,可以轻松地将查询速度提高一倍、三倍或更多。
【讨论】:
以上是关于如何使用多个 INNER JOIN 加快查询速度的主要内容,如果未能解决你的问题,请参考以下文章
是否应该在 SQLite 中使用 GROUP BY 在 UNION 上进行 INNER JOIN 花费数小时?
如何将 IN 条件转换为 INNER JOIN 条件 - 加入速度较慢