sql查询连接多个表 - 太慢(8个表)

时间:2009-04-30 09:02:49

标签: sql performance join

我正在尝试将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)

我执行它时甚至看不到查询结果,有什么方法可以加快速度吗? :)赞赏任何类型的帮助,但最好只有一个查询(外部应用程序规则)

提前致谢

8 个答案:

答案 0 :(得分:53)

我遇到了类似的问题,几个查找表连接到一个大表,所有id字段都被索引。为了监视联接对查询时间执行的影响,我多次运行我的查询(限制到前100行),每次都向另一个表添加一个Join。加入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 :(得分:28)

根据表中的数据量,您可能需要在要连接的列上放置索引。查询速度通常很慢,因为缺少正确的索引。

此外:

LEFT JOIN比INNER JOIN慢(虽然这取决于你正在做的事情) - 你能用内连接完成你想要的东西吗?

答案 2 :(得分:5)

我们谈论了多少数据?可能是您拥有大量数据,并且在查询过程结束时运行where子句,您需要在过滤之前加入大量数据。

在这种情况下,最好尽快过滤数据,这样如果你可以在第一个内部选择中限制来自T1的数据,那么所有其他连接将加入一组更有限的数据。

Select <your fields> from
(
Select * from t1 where t1_id = t1_value
) t1

Inner join t2
on t1.ID = t2.ID
...

如果它不是大量的数据;检查索引是否正确然后检查服务器类型的东西;索引碎片;磁盘队列等。

答案 3 :(得分:4)

如果您可以发布查询的解释计划,那会有所帮助。

但是,首先,您在连接中使用的所有字段都有索引吗? 像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 

但是,如果有一个好的查询规划器,那么它应该与连接不同。

答案 4 :(得分:1)

如果您需要t1的所有行,并且您在其他表的主键(我猜它也是聚簇索引)上保持连接,则无法提高查询的速度。

要提高性能,您需要减少结果集或执行讨厌的技巧(例如,制作数据的非规范化副本)。

答案 5 :(得分:1)

根据您的查询计划,我可以得出结论,称为snq的表格没有关于它们正在加入的字段的索引。

由于这些表格中有很多行(笛卡尔积中约为400,000行)而MySQL只有JOIN的行使用NESTED LOOPS这真的需要永远。

在这些表上创建索引或将联接字段定义为PRIMARY KEY

答案 6 :(得分:0)

正如我所看到的,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子句的列上创建它。

答案 7 :(得分:-1)

根据您的SQL Server版本,只需将查询放入存储过程可能会产生很大的不同。在您首先尝试其他优化之后尝试这一点。(是的,我知道有缓存的执行计划和其他内部服务器优化,但在我的实际实际经验中,存储过程可以更快地执行。)