Mysql
 sql >> Base de données >  >> RDS >> Mysql

Puis-je forcer mysql à effectuer d'abord une sous-requête ?

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 .