我该如何优化这个MySQL查询?

时间:2010-09-14 20:14:25

标签: sql mysql

有人可以解释为什么通过子查询添加组会使此查询花费这么长时间(30秒):

SELECT *
FROM aggregate_songlist AS a
INNER JOIN musical_works AS m 
ON a.musical_work_id = m.id
WHERE m.genre='rock' AND m.id NOT IN 
(SELECT sources.musical_work_id FROM sources GROUP BY sources.musical_work_id HAVING COUNT(sources.musical_work_id) > 8)

如果我删除'group by'(并增加子查询的结果),则需要0.07秒:

SELECT *
FROM aggregate_songlist AS a
INNER JOIN musical_works AS m 
ON a.musical_work_id = m.id
WHERE m.genre='rock' AND m.id NOT IN 
(SELECT sources.musical_work_id FROM sources)

子查询中没有外部引用,所以它只应执行一次,对吧?自己执行:

SELECT sources.musical_work_id FROM sources GROUP BY sources.musical_work_id HAVING COUNT(sources.musical_work_id) > 8

只需0.01秒。

有任何解释吗?有关如何更改它的任何建议吗?

3 个答案:

答案 0 :(得分:6)

  

子查询中没有外部引用,所以它只应执行一次,对吧?

你会这么认为,但不是。如果查看EXPLAIN,您将看到子查询被称为“依赖子查询”而不是“子查询”。这意味着每次都会重新执行。这是MySQL 5.0中的known bug,并在MySQL 6.0中修复。

要解决此问题,您可以使用其他方法之一来检查另一个表中是否存在行。三个常用方法是NOT IN,NOT EXISTS和LEFT JOIN ... WHERE ... IS NULL,所以你还有两个选项。

答案 1 :(得分:2)

NOT IN可能是你的问题。尝试加入它(你必须翻转HAVING子句):

SELECT *
FROM aggregate_songlist AS a
INNER JOIN musical_works AS m 
ON a.musical_work_id = m.id
LEFT JOIN (
      SELECT sources.musical_work_id FROM sources 
      GROUP BY sources.musical_work_id   
      HAVING COUNT(sources.musical_work_id) <= 8) AS t
ON m.id = t.musical_work_id
WHERE m.genre='rock' AND t IS NULL

[更新以反映@Mark Byers的评论,谢谢!]

答案 2 :(得分:0)

SELECT *
FROM 
aggregate_songlist AS a
INNER JOIN musical_works AS m 
ON a.musical_work_id = m.id
LEFT JOIN (
      SELECT sources.musical_work_id FROM sources 
      GROUP BY sources.musical_work_id   
      HAVING COUNT(sources.musical_work_id) <= 8)
AS t
ON m.id = t.musical_work_id
WHERE
m.genre='rock' AND
t.musical_work_id IS NULL
相关问题