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?
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?
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:
Depuis combien de temps cela a-t-il été le cas? –
@Ian: quoi exactement? – Quassnoi
@Qnassnoi, que l'efficacité est à peu près la même –
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 ...
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.
@duffymo: tout est faux. – Quassnoi
Pourquoi est-ce fermé? Je suis curieux de connaître la raison aussi. –
@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