2011-07-21 1 views
6

J'ai entendu beaucoup de gens au fil des ans disent que:L'utilisation de "NOT EXISTS" est-elle considérée comme une mauvaise pratique SQL?

« rejoindre » les opérateurs sont préférés sur « NOT EXISTS »

Pourquoi?

+4

@duffymo: tout est faux. – Quassnoi

+1

Pourquoi est-ce fermé? Je suis curieux de connaître la raison aussi. –

+0

@Ziayo: probablement à cause des mots "beaucoup de gens". Si libellé "sont des jointures plus efficaces que" NOT EXISTS ", ce serait une question parfaite avec" faits, références, ou expertise spécifique ". – Quassnoi

Répondre

9

En MySQL, Oracle, SQL Server et PostgreSQL, NOT EXISTS est de la même efficacité ou encore plus efficace que LEFT JOIN/IS NULL. Alors qu'il peut sembler que "la requête interne doit être exécutée pour chaque enregistrement de la requête externe" (ce qui semble être mauvais pour NOT EXISTS et pire encore pour NOT IN, puisque cette dernière requête n'est même pas corrélée), être optimisé aussi bien que toutes les autres requêtes sont optimisées, en utilisant les méthodes appropriées anti-join.

En fait, peut être moins efficace que NOT EXISTS/NOT IN dans le cas d'une colonne de cardinalité non indexée ou faible dans la table interne.

On entend souvent que MySQL est "particulièrement mauvais dans le traitement des sous-requêtes".

Cela vient du fait que MySQL n'est capable d'aucune méthode de jointure autre que des boucles imbriquées, ce qui limite considérablement ses capacités d'optimisation.

Le seul cas où une requête bénéficierait de sous-requête de réécriture comme une jointure serait ceci:

SELECT * 
FROM big_table 
WHERE big_table_column IN 
     (
     SELECT small_table_column 
     FROM small_table 
     ) 

small_table ne sera pas interrogé complètement pour chaque enregistrement big_table: bien qu'il ne semble pas être corrélée, il sera implicitement corrélé par l'optimiseur de requêtes et en fait réécrite à un EXISTS (en utilisant index_subquery pour rechercher la première chose si nécessaire si small_table_column est indexé)

Mais big_table serait toujours leader, ce qui rend t La requête complète dans big * LOG(small) plutôt que small * LOG(big) lit.

Cela pourrait être réécrite comme

SELECT DISTINCT bt.* 
FROM small_table st 
JOIN big_table bt 
ON  bt.big_table_column = st.small_table_column 

Cependant, cela n'améliorer NOT IN (par opposition à IN). Dans MySQL, NOT EXISTS et LEFT JOIN/IS NULL sont presque les mêmes, puisque avec des boucles imbriquées la table gauche devrait toujours être en tête dans un LEFT JOIN.

Vous pouvez lire ces articles:

+0

Depuis combien de temps cela a-t-il été le cas? –

+0

@Ian: quoi exactement? – Quassnoi

+0

@Qnassnoi, que l'efficacité est à peu près la même –

0

Cela peut avoir à voir avec le processus d'optimisation ... NOT EXISTS implique une sous-requête, et les "optimiseurs" ne font généralement pas de sous-requêtes. D'un autre côté, les jointures peuvent être traitées plus facilement ...

0

Je pense que c'est un cas spécifique à MySQL. MySQL n'optimise pas la sous-requête dans les clauses IN/not in/any/not exists, et effectue réellement la sous-requête pour chaque ligne correspondant à la requête externe. Pour cette raison, dans MySQL, vous devez utiliser join. Dans PostgreSQL cependant, vous pouvez simplement utiliser la sous-requête.

+1

Il optimise toutes ces clauses. S'il vous plaît lire http://explainextended.com/2009/09/18/not-in-vs-not-exists-vs-left-join-is-null-mysql/ – Quassnoi

+0

@Darhazer, vous semblez coincé dans MySQL version 4. – Johan

+0

@Johan: ... qui a également optimisé toutes ces constructions. – Quassnoi

Questions connexes