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]
Si la table interne est correctement indexée, la sous-requête ici n'est pas du tout "exécutée" au sens strict du terme.
Puisque la sous-requête fait partie d'un IN
expression, la condition est poussée dans la sous-requête et elle est transformée en un EXISTS
.
En fait, cette sous-requête est évaluée à chaque étape :
EXISTS
(
SELECT NULL
FROM [...]
WHERE id = table1.id
)
Vous pouvez en fait le voir dans la description détaillée fournie par EXPLAIN EXTENDED
.
C'est pourquoi elle s'appelle DEPENDENT SUBQUERY
:le résultat de chaque évaluation dépend de la valeur de table1.id
. La sous-requête en tant que telle n'est pas corrélée, c'est la version optimisée qui est corrélée.
MySQL
évalue toujours EXISTS
clause après les filtres les plus simples (puisqu'ils sont beaucoup plus faciles à évaluer et qu'il est probable que la sous-requête ne soit pas évaluée du tout).
Si vous souhaitez que la sous-requête soit évaluée en une seule fois, réécrivez la requête comme suit :
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]
Cela force la sous-requête à être en tête dans la jointure, ce qui est plus efficace si la sous-requête est petite par rapport à table_1
, et moins efficace si la sous-requête est volumineuse par rapport à table_1
.
S'il y a un index sur [...].id
utilisé dans la sous-requête, la sous-requête sera effectuée à l'aide d'un INDEX FOR GROUP-BY
.