sql 查询连接多个表 - 太慢(8 个表)
Posted
技术标签:
【中文标题】sql 查询连接多个表 - 太慢(8 个表)【英文标题】:sql query joins multiple tables - too slow (8 tables) 【发布时间】:2010-10-22 19:18:04 【问题描述】:我正在尝试将 8 个表合并为一个以创建其他应用程序使用的索引,我的查询是这样的:(我的 mysql 技能非常业余)
SELECT t1_id, t2_name, t3_name, t4_name, t5_name,
t6_name, t7_name, t8_name, t9_name
FROM t1
LEFT JOIN t2 ON (t1_id = t2_id)
LEFT JOIN t3 ON (t3_id = t1_id)
LEFT JOIN t4 ON (t4_id = t1_id)
LEFT JOIN t5 ON (t5_id = t1_id)
LEFT JOIN t6 ON (t6_id = t1_id)
LEFT JOIN t7 ON (t7_id = t1_id)
LEFT JOIN t8 ON (t8_id = t1_id)
LEFT JOIN t9 ON (t9_id = t1_id)
执行时我什至看不到查询结果,有什么方法可以加快速度吗? :) 任何形式的帮助都值得赞赏,但最好只有一个查询(在应用程序规则之外)
提前致谢
【问题讨论】:
【参考方案1】:我有一个类似的问题,几个查找表连接到一个所有 id 字段都被索引的大表。为了监控联接对查询时间执行的影响,我多次运行查询(限制为前 100 行),每次都将联接添加到附加表中。加入 12 个表后,查询执行时间没有明显变化。当我加入第 13 个表时,执行时间跃升至 1 秒;第14桌4秒,第15桌20秒,第16桌90秒。
Keijro 建议使用相关子查询而不是连接,例如
SELECT t1_id,
(select t2_name from t2 where t1_id = t2_id),
(select t3_name from t3 where t1_id = t3_id),
(select t4_name from t4 where t1_id = t4_id),
(select t5_name from t5 where t1_id = t5_id),
(select t6_name from t6 where t1_id = t6_id),
(select t7_name from t7 where t1_id = t7_id),
(select t8_name from t8 where t1_id = t8_id),
(select t9_name from t9 where t1_id = t9_id) FROM t1
显着提高了查询性能。事实上,子查询似乎并没有延长执行查询的时间(查询几乎是即时的)。
我有点惊讶,因为我认为相关子查询的性能比连接差。
【讨论】:
如果可以的话,我会给你更多的 +1。我遇到了完全相同的问题,这个解决方案非常有效。来自 MSSQL/Oracle 背景的感知智慧是尽可能避免相关子查询,这是非常违反直觉的,但它确实有效。阅读它似乎可能是因为 MySQL 将连接处理为嵌套循环。 我来自 15 个表连接。即使有索引,查询仍然需要我从 50 个结果限制中花费 1 或 2 秒。我将尝试使用您的建议重写大方法。谢谢!【参考方案2】:根据表中的数据量,您可能需要在要连接的列上放置索引。查询速度慢通常归结为在正确的位置缺少索引。
还有:
LEFT JOIN 比 INNER JOIN 慢(尽管这取决于您的具体操作) - 您可以使用内部连接完成您正在寻找的内容吗?
【讨论】:
可以很好地解释内连接和左连接之间的区别:内连接不包括未找到数据的行,而左连接(或外连接)则包含。也就是说,如果说 t8 缺少与 t1_id 对应的 id,则根本不会包含该行(即使还有其他具有该 id 的表) 同意这两点。使用 INNER JOINS 并确保您要加入的字段有索引。 但请参阅下面有关使用相关子查询的答案。我有一个 15 个连接表(所有内部连接都用于解码主索引),如果可以将 10 个连接放入相关子查询而不是连接中,它的运行速度会快 1000 倍【参考方案3】:如果您可以发布查询的解释计划,这将有所帮助。
但是,首先,您对连接中使用的所有字段都有索引?
类似CREATE INDEX ix_t2_id on t2 (t2_id, t2_name);
您可以执行类似
的操作,而不是连接SELECT t1_id,
(select t2_name from t2 where t1_id = t2_id),
(select t3_name from t3 where t1_id = t3_id),
(select t4_name from t4 where t1_id = t4_id),
(select t5_name from t5 where t1_id = t5_id),
(select t6_name from t6 where t1_id = t6_id),
(select t7_name from t7 where t1_id = t7_id),
(select t8_name from t8 where t1_id = t8_id),
(select t9_name from t9 where t1_id = t9_id)
FROM t1
但是,对于一个好的查询计划器,这应该与连接没有什么不同。
【讨论】:
感谢您的回答,这是解释计划:1 SIMPLE r ALL NULL NULL NULL NULL 4977 1 SIMPLE m ref release release 4 main.r.r_id 2 1 SIMPLE t ref release release 4 main。 r.r_id 2 1 SIMPLE s ALL NULL NULL NULL NULL 4889 1 SIMPLE mu ref release release 4 main.r.r_id 2 1 SIMPLE n ALL NULL NULL NULL NULL 6 1 SIMPLE q ALL NULL NULL NULL NULL 13 1 SIMPLE o ref release release 4 main.r.r_id 2 1 SIMPLE g ref release release 4 main.r.r_id 2 我不确定内联选择是提高 SQL 性能的好方法。 有些书称它们为相关子查询。它们是 From 之前的其他 select 语句中的选择;它们是逐行评估的,因此对于大型数据集,它们的效率非常低。 没错,它们大多应该被避免,但我有几次它们对性能做出了很大贡献,所以在某些情况下应该考虑它们。【参考方案4】:我们在谈论多少数据?可能是您有大量数据,并且由于 where 子句在查询过程结束时运行,您在过滤之前加入了大量数据。
在这种情况下,最好尽快过滤数据,因此如果您可以在第一个内部选择中限制来自 T1 的数据,则所有其他连接将连接到更有限的数据集。
Select <your fields> from
(
Select * from t1 where t1_id = t1_value
) t1
Inner join t2
on t1.ID = t2.ID
...
如果不是大量数据;检查您的索引是否正确,然后检查服务器类型;索引碎片;磁盘队列等
【讨论】:
是否还有要检查的 t1_value?他/她在问题中没有这样说。【参考方案5】:如果你需要t1的所有行,而你在其他表的主键(我猜也是聚集索引)上留下join,那么查询速度是没有办法提高的。
要提高性能,您要么需要减少结果集,要么执行一些令人讨厌的技巧(例如,制作数据的非规范化副本)。
【讨论】:
【参考方案6】:根据您的查询计划,我可以得出结论,称为 s
、n
和 q
的表在它们要连接的字段上没有索引。
由于这些表中有很多行(大约400,000
行在他们的笛卡尔积中)并且MySQL
的唯一方法是使用JOIN
是使用NESTED LOOPS
,它真的需要很长时间。
在这些表上创建索引或将连接字段定义为PRIMARY KEY
。
【讨论】:
【参考方案7】:如我所见,t1 表是与所有表连接的表,而不是将它们放在具有如此多连接的单个查询中,您可以尝试类似这样的不同查询的联合。
SELECT t1_id, t2_name
FROM t1 LEFT JOIN t2 ON (t1_id = t2_id)
union
SELECT t1_id, t3_name
FROM t1 LEFT JOIN t3 ON (t1_id = t3_id)
但是,在这种情况下,您将获得的结果将不是 8 列,而是只有 1 列。不确定这是否适合您。
在您实施的任何解决方案中,您必须做的另一件事是 - 在所有表上创建适当的索引。索引列的最佳实践是在最常用于连接或 where 子句的列上创建它。
【讨论】:
【参考方案8】:当您使用的数据集太大以至于在执行连接时超出了工作内存时,连接速度会显着降低。然后,Postgres 将在运行过程中将其工作保存到磁盘。这就是为什么您可能会在第 n 次连接之后才看到速度变慢,而不管您要连接哪些表,或者您是否正确配置了索引。
在我的例子中,EXPLAIN
只显示了几万行,没什么好写的。但我了解到,即使在加入期间发生减速,加入也可能不是问题。在我的例子中,罪魁祸首原来是一个非常大的 uuid[] 列,其中包含很多条目。我从查询中排除了这一列,它加快了一切速度。
【讨论】:
【参考方案9】:根据您的 SQL Server 版本,简单地将查询放入存储过程可能会产生很大的不同。先尝试其他优化后再试试这个。(是的,我知道有缓存的执行计划和其他内部服务器优化,但根据我的实际经验,存储过程可以更快地执行。)
【讨论】:
以上是关于sql 查询连接多个表 - 太慢(8 个表)的主要内容,如果未能解决你的问题,请参考以下文章