INNER JOIN与LEFT JOIN的奇怪性能问题

时间:2010-12-09 06:00:23

标签: mysql performance join

我使用的查询与此类似:

SELECT `episodes`.*, IFNULL(SUM(`views_sum`.`clicks`), 0) as `clicks`
FROM `episodes`, `views_sum`
WHERE `views_sum`.`index` = "episode" AND `views_sum`.`key` = `episodes`.`id`
GROUP BY `episodes`.`id`

...需要~0.1s才能执行。但这有问题,因为有些episodes没有相应的views_sum行,因此这些剧集不会包含在结果中。

当相应的views_sum行不存在时,我想要的是NULL值,所以我尝试使用LEFT JOIN代替:

SELECT `episodes`.*, IFNULL(SUM(`views_sum`.`clicks`), 0) as `clicks`
FROM `episodes`
LEFT JOIN `views_sum` ON (`views_sum`.`index` = "episode" AND `views_sum`.`key` = `episodes`.`id`)
GROUP BY `episodes`.`id`

此查询生成相同的列,并且还包括第一个查询中缺少的几行。

但是,第二个查询需要10倍的时间!一秒钟。

为什么结果如此相似的执行时间之间存在如此巨大的差异?没有接近行的10倍 - 从第一个查询开始就是60,从第二个查询开始是70。这并不是说额外的10行没有views总和!

任何灯光都会受到高度赞赏!

episodes.idviews_sum.indexviews_sum.key上有索引。)

修改

我从上面复制粘贴了SQL,这里是EXPLAINs,按顺序:

id  select_type table       type    possible_keys   key         key_len     ref                         rows    Extra
1   SIMPLE      views_sum   ref     index,key       index       27          const                       6532    Using where; Using temporary; Using filesort
1   SIMPLE      episodes    eq_ref  PRIMARY         PRIMARY     4           db102914_itw.views_sum.key  1       Using where

id  select_type table       type    possible_keys   key         key_len     ref                         rows    Extra
1   SIMPLE      episodes    ALL     NULL            NULL        NULL        NULL                        70      Using temporary; Using filesort
1   SIMPLE      views_sum   ref     index,key       index       27          const                       6532 

4 个答案:

答案 0 :(得分:1)

这是我经过多次迭代后最终提出的查询。 (SQL_NO_CACHE标志在那里,所以我可以测试执行时间。)

SELECT SQL_NO_CACHE e.*, IFNULL(SUM(vs.`clicks`), 0) as `clicks`

FROM `episodes` e

LEFT JOIN
(SELECT * FROM `views_sum` WHERE `index` = "episode") vs
ON vs.`key` = e.`id`

GROUP BY e.`id`

因为ON condtion views_sum.index = "episode"是静态的,即不依赖于它所加入的行,所以我首先使用子查询来限制views_sum,从而获得了巨大的性能提升。 加入之前的表。

我的查询现在需要约0.2秒。甚至更好的是,随着您增加查询的偏移量,时间不会增长(与我的第一次LEFT JOIN尝试不同)。它保持不变,即使您对clicks列进行排序。

答案 1 :(得分:1)

您应该在views_sumindexviews_sumkey上添加组合索引。我怀疑如果我看一下这些名字你会一直使用这两个字段。另外,我会重写第一个查询以使用正确的INNER JOIN子句而不是过滤的笛卡尔积。

我怀疑如果你这样做,两个查询的性能会更加接近。而且,更重要的是,它比现在快得多。

编辑:考虑一下,我可能会在该索引中添加第三列:views_sumclicks,它可能用于SUM。但请记住,多列索引只能从左到右使用。

答案 2 :(得分:0)

关于索引的全部内容。您将不得不稍微使用它或在此处发布您的数据库架构。就像一个粗略的猜测我会说你应该确保你有一个关于views_sum.key的索引。

答案 3 :(得分:0)

通常情况下,LEFT JOIN会慢于INNER JOINCROSS JOIN,因为它必须以不同方式查看第一个表格。换句话说,时间上的差异与结果的大小无关,但左表的完整大小

我也想知道你是否要求MySQL为你解决你自己应该做的事情。具体来说,SUM()函数通常需要GROUP BY子句。