Existe-t-il une bonne pratique entre utiliser un format LEFT JOIN ou un format NOT EXISTS?
Quel est l'avantage d'utiliser l'un sur l'autre?
Si aucun, lequel devrait être préféré?
SELECT *
FROM tableA A
LEFT JOIN tableB B
ON A.idx = B.idx
WHERE B.idx IS NULL
SELECT *
FROM tableA A
WHERE NOT EXISTS
(SELECT idx FROM tableB B WHERE B.idx = A.idx)
J'utilise des requêtes dans Access sur une base de données SQL Server.
sql-server
join
exists
Michael Richardson
la source
la source
WHERE A.idx NOT IN (...)
est pas identique en raison du comportement trivalentNULL
(c.NULL
-à-n'est pas égal àNULL
(ni inégale), donc si vous avez uneNULL
entableB
vous obtiendrez des résultats inattendus!)Réponses:
La plus grande différence ne réside pas dans la jointure ni dans la jonction, elle est (comme écrit), la
SELECT *
.Dans le premier exemple, vous obtenez toutes les colonnes des deux
A
etB
, alors que dans le deuxième exemple, vous n’obtenez que des colonnesA
.Dans SQL Server, la deuxième variante est légèrement plus rapide dans un exemple très simple:
Créez deux exemples de tables:
Insérer 10 000 lignes dans chaque tableau:
Supprimer tous les 5 rangs de la deuxième table:
Effectuez les deux
SELECT
variantes d'instruction de test :Plans d'exécution:
La deuxième variante n'a pas besoin d'effectuer l'opération de filtrage car elle peut utiliser l'opérateur anti-jointure gauche.
la source
Logiquement, ils sont identiques, mais
NOT EXISTS
sont plus proches de l'AntiSemiJoin que vous demandez et sont généralement préférés. Cela met également en évidence le fait que vous ne pouvez pas accéder aux colonnes dans B, car il est uniquement utilisé comme filtre (au lieu de les avoir avec des valeurs NULL).Il y a de nombreuses années (SQL Server 6.0 ish),
LEFT JOIN
était plus rapide, mais ce n'est pas le cas depuis très longtemps. Ces jours-ci,NOT EXISTS
est légèrement plus rapide.Le principal impact d’Access est que la
JOIN
méthode doit terminer la jointure avant de la filtrer, en construisant l’ensemble joint en mémoire. Son utilisationNOT EXISTS
vérifie la ligne mais n'attribue pas d'espace pour les colonnes. De plus, il cesse de chercher dès qu'il trouve une ligne. Les performances varient un peu plus dans Access, mais une règle générale est que cela aNOT EXISTS
tendance à être un peu plus rapide. Je serais moins enclin à dire que c'est la "meilleure pratique", car il y a plus de facteurs impliqués.la source
Une exception que j'ai remarquée à la
NOT EXISTS
supériorité (même marginale) de l'LEFT JOIN ... WHERE IS NULL
utilisation de serveurs liés .En examinant les plans d'exécution, il apparaît que l'
NOT EXISTS
opérateur est exécuté de manière imbriquée en boucle. Pour cela, il est exécuté ligne par ligne (ce qui est logique, je suppose).Exemple de plan d'exécution démontrant ce comportement:
la source
INSERT INTO #t (a,b,c) SELECT a,b,c FROM LinkedServer.database.dbo.table WHERE x=y
puis en exécutant laNOT EXISTS (...)
clause sur cette copie temporaire de la base de données.En général, le moteur créera un plan d'exécution basé essentiellement sur:
Pour 4):
Le plan "pas existe" encourage un plan basé sur la recherche sur la table B. C'est un bon choix lorsque la table A est petite et que la table B est grande (et qu'un index existe sur B).
Le plan "anti-jointure" est un bon choix lorsque la table A est très grande ou la table B est très petite ou pas d'index sur B et renvoie un jeu de résultats volumineux.
Cependant, il ne s'agit que d'un "encouragement", comme une entrée pondérée. Un fort (1), (2), (3) fait souvent le choix de (4) théorique.
(Ignorer l'effet de votre exemple renvoyant différentes colonnes en raison de la *, adressée par @MaxVernon answer.).
la source