我可以强制mysql首先执行子查询吗?

时间:2009-11-19 21:29:07

标签: sql mysql subquery

我有这样的查询:

SELECT `table_1`.* from `table_1`
  INNER JOIN `table_2` [...]
  INNER JOIN `table_3` [...]
WHERE `table_1`.`id` IN(
  SELECT `id` FROM [...]
)
AND [more conditions]

当我使用EXPLAIN时,最后会有'DEPENDENT SUBQUERY',但我希望在其他条件之前先执行此子查询。

有可能吗?

5 个答案:

答案 0 :(得分:14)

SELECT  `table_1`.*
FROM    `table_1`
INNER JOIN
        `table_2` [...]
INNER JOIN
        `table_3` [...]
WHERE   `table_1`.`id` IN
        (
        SELECT  `id`
        FROM    [...]
        )
        AND [more conditions]

如果内部表被正确编入索引,则严格意义上的子查询根本不会“执行”。

由于子查询是IN表达式的一部分,因此将条件推送到子查询中并将其转换为EXISTS

实际上,每个步骤都会对此子查询进行评估:

EXISTS
(
SELECT  NULL
FROM    [...]
WHERE   id = table1.id
)

您实际上可以在EXPLAIN EXTENDED提供的详细说明中看到它。

这就是为什么它被称为DEPENDENT SUBQUERY:每次评估的结果取决于table1.id的值。这样的子查询不相关,它是相关的优化版本。

MySQL总是在更简单的过滤器之后评估EXISTS子句(因为它们更容易评估,并且有可能根本不评估子查询)。

如果希望一次性评估子查询,请按以下步骤重写查询:

SELECT  table_1.*
FROM    (
        SELECT  DISTINCT id
        FROM    [...]
        ) q
JOIN    table_1
ON      table_1.id = q.id
JOIN    table_2
ON      [...]
JOIN    table_3
ON      [...]
WHERE   [more conditions]

这会强制子查询在联接中处于领先地位,如果子查询与table_1相比较小,则效率更高,如果子查询与table_1相比较大,则效率较低。

如果子查询中使用的[...].id上有索引,则子查询将使用INDEX FOR GROUP-BY执行。

答案 1 :(得分:3)

这是mysql中的已知错误:http://bugs.mysql.com/bug.php?id=25926

一个有用的解决方法是将子查询下推到另一个select * from (subquery) as dt类型子查询中。

答案 2 :(得分:2)

您可以先将子查询的结果选择到临时表中,然后在主查询中加入它。

答案 3 :(得分:2)

最好的方法是将table1的WHERE条件放入FROM子句中的子查询中。 EG:

SELECT `table_1`.* 
FROM (
      SELECT * FROM `table_1` WHERE `table_1`.`id` IN (...)
     )
  INNER JOIN `table_2` [...]
  INNER JOIN `table_3` [...]
WHERE [more conditions]

答案 4 :(得分:-1)

不幸的是,不,你不能。子查询实际上为外部查询中的每一行运行一次。

我实际建议您将此转换为另一个联接,使用table_1.id作为另一个表的键。