Mysql
 sql >> Database >  >> RDS >> Mysql

Posso forzare mysql a eseguire prima la sottoquery?

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]

Se la tabella interna è indicizzata correttamente, la sottoquery qui non viene "eseguita" in senso stretto.

Poiché la sottoquery fa parte di un IN espressione, la condizione viene inserita nella sottoquery e viene trasformata in un EXISTS .

In effetti, questa sottoquery viene valutata ad ogni passaggio:

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

Puoi effettivamente vederlo nella descrizione dettagliata fornita da EXPLAIN EXTENDED .

Ecco perché si chiama DEPENDENT SUBQUERY :il risultato di ogni valutazione dipende dal valore di table1.id . La sottoquery in quanto tale non è correlata, è la versione ottimizzata che è correlata.

MySQL valuta sempre EXISTS clausola dopo i filtri più semplici (poiché sono molto più facili da valutare e c'è la probabilità che la sottoquery non venga valutata affatto).

Se vuoi che la sottoquery venga valutata tutta in una volta, riscrivi la query come segue:

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]

Ciò costringe la sottoquery a condurre il join, il che è più efficiente se la sottoquery è piccola rispetto a table_1 e meno efficiente se la sottoquery è grande rispetto a table_1 .

Se è presente un indice su [...].id utilizzato nella sottoquery, la sottoquery verrà eseguita utilizzando un INDEX FOR GROUP-BY .