我使用的查询与此类似:
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.id
、views_sum.index
、views_sum.key
上有索引。)
编辑:
我从上面复制粘贴了 SQL,这里是 EXPLAIN,按顺序:
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
最佳答案
这是我在多次迭代后最终得出的查询。 (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 条件 views_sum.index = "episode"
是静态的,即不依赖于它所连接的行,我能够通过首先使用 加入前限制 views_sum
表的子查询。
我的查询现在需要大约 0.2 秒。更好的是,时间不会随着查询的偏移量的增加而增加(与我的第一次 LEFT JOIN 尝试不同)。它保持不变,即使您对 clicks
列进行排序也是如此。
关于mysql - INNER JOIN 与 LEFT JOIN 的奇怪性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4395336/