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
执行。
按下子查询的问题是,如果子查询依赖于外部查询的常量部分,则这是不可能的(请参阅https://stackoverflow.com/questions/44859809/how-to-optimize-dependent-subquery -with-constant-expression) – andig 2017-07-01 10:43:06