我使用的查询与此类似:
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,这里是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
答案 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_sum
。index
和views_sum
。key
上添加组合索引。我怀疑如果我看一下这些名字你会一直使用这两个字段。另外,我会重写第一个查询以使用正确的INNER JOIN子句而不是过滤的笛卡尔积。
我怀疑如果你这样做,两个查询的性能会更加接近。而且,更重要的是,它比现在快得多。
编辑:考虑一下,我可能会在该索引中添加第三列:views_sum
。clicks
,它可能用于SUM。但请记住,多列索引只能从左到右使用。
答案 2 :(得分:0)
关于索引的全部内容。您将不得不稍微使用它或在此处发布您的数据库架构。就像一个粗略的猜测我会说你应该确保你有一个关于views_sum.key的索引。
答案 3 :(得分:0)
通常情况下,LEFT JOIN
会慢于INNER JOIN
或CROSS JOIN
,因为它必须以不同方式查看第一个表格。换句话说,时间上的差异与结果的大小无关,但左表的完整大小。
我也想知道你是否要求MySQL为你解决你自己应该做的事情。具体来说,SUM()
函数通常需要GROUP BY
子句。