160 votes

Sous-requêtes et jointures

J'ai remanié une section lente d'une application que nous avons héritée d'une autre entreprise pour utiliser une jointure interne au lieu d'une sous-requête :

WHERE id IN (SELECT id FROM ...)

La requête remaniée est environ 100 fois plus rapide. (~50 secondes à ~0,3) Je m'attendais à une amélioration, mais quelqu'un peut-il expliquer pourquoi elle est si radicale ? Les colonnes utilisées dans la clause where étaient toutes indexées. Est-ce que SQL exécute la requête dans la clause where une fois par ligne ou quelque chose comme ça ?

Mise à jour - Expliquez les résultats :

La différence se situe dans la deuxième partie de la requête "where id in ()" -

2   DEPENDENT SUBQUERY  submission_tags ref st_tag_id   st_tag_id   4   const   2966    Using where

contre 1 ligne indexée avec la jointure :

    SIMPLE  s   eq_ref  PRIMARY PRIMARY 4   newsladder_production.st.submission_id  1   Using index

4 votes

Duplicata possible de Jointure et sous-requête

2 votes

Pas un doublon. Cette question porte spécifiquement sur la différence de performance frappante. L'autre question est plus générale, ouverte sur les avantages et les inconvénients de chaque approche et sur les raisons pour lesquelles une approche semble plus populaire.

0 votes

@simhumileco Ce n'est pas une amélioration, ce n'est pas une différence, c'est contraire à ce que l'auteur a écrit & ce genre d'édition pour le style du code est inapproprié. Quand dois-je modifier le code ?

160voto

Jeffrey L Whitledge Points 27574

Une "sous-requête corrélée" (c'est-à-dire une sous-requête dont la condition "where" dépend des valeurs obtenues à partir des lignes de la requête contenante) sera exécutée une fois pour chaque ligne. Une sous-requête non corrélée (une sous-requête dans laquelle la condition where est indépendante de la requête contenue) s'exécutera une fois au début. Le moteur SQL fait cette distinction automatiquement.

Mais, ouais, explain-plan te donnera les détails cochons.

3 votes

Veuillez noter que DEPENDENT SUBQUERY signifie exactement la même chose que "sous-requête corrélée".

38voto

Sklivvz Points 16412

Vous exécutez la sous-requête une fois pour chaque ligne alors que la jointure se fait sur les index.

5 votes

Je ne pense pas que ce soit vrai. Le moteur SQL devrait exécuter la sous-requête une seule fois et utiliser le résultat comme une liste.

8 votes

Cela dépend - si la sous-requête est corrélée d'une manière ou d'une autre avec la requête externe (utilise ses données), elle est exécutée à chaque ligne.

4 votes

C'est probablement vrai dans ce cas, mais ce n'est pas vrai en général.

16voto

Giuseppe Maxia Points 236

Voici un exemple de la façon dont les sous-requêtes sont évaluées dans MySQL 6.0 .

Le nouvel optimiseur convertira ce type de sous-requêtes en jointures.

0 votes

C'est un excellent article sur l'optimiseur amélioré de MySQL 6.0, merci.

7voto

scotta Points 226

Lancez le plan d'explication sur chaque version, il vous dira pourquoi.

6voto

pfranza Points 1504

Avant que les requêtes ne soient exécutées sur l'ensemble de données, elles sont soumises à un optimiseur de requêtes, qui tente d'organiser la requête de manière à supprimer le plus rapidement possible un maximum de tuples (lignes) de l'ensemble de résultats. Souvent, lorsque vous utilisez des sous-requêtes (en particulier les mauvaises), les tuples ne peuvent pas être retirés du jeu de résultats avant que la requête externe ne commence à s'exécuter.

Sans voir la requête, il est difficile de dire ce qui était si mauvais dans l'original, mais je pense que c'était quelque chose que l'optimiseur ne pouvait pas améliorer. L'exécution de 'explain' vous montrera la méthode de l'optimiseur pour récupérer les données.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X