Mise à jour :
Ces articles de mon blog décrivent plus en détail les différences entre les méthodes :
NOT IN
vsNOT EXISTS
vsLEFT JOIN / IS NULL
:SQL Server
NOT IN
vsNOT EXISTS
vsLEFT JOIN / IS NULL
:PostgreSQL
NOT IN
vsNOT EXISTS
vsLEFT JOIN / IS NULL
:Oracle
NOT IN
vsNOT EXISTS
vsLEFT JOIN / IS NULL
:MySQL
Il existe trois façons de faire une telle requête :
-
LEFT JOIN / IS NULL
:SELECT * FROM common LEFT JOIN table1 t1 ON t1.common_id = common.common_id WHERE t1.common_id IS NULL
-
NOT EXISTS
:SELECT * FROM common WHERE NOT EXISTS ( SELECT NULL FROM table1 t1 WHERE t1.common_id = common.common_id )
-
NOT IN
:SELECT * FROM common WHERE common_id NOT IN ( SELECT common_id FROM table1 t1 )
Lorsque table1.common_id
n'accepte pas la valeur null, toutes ces requêtes sont sémantiquement identiques.
Lorsqu'il est nullable, NOT IN
est différent, puisque IN
(et, par conséquent, NOT IN
) renvoie NULL
lorsqu'une valeur ne correspond à rien dans une liste contenant un NULL
.
Cela peut prêter à confusion mais peut devenir plus évident si nous rappelons la syntaxe alternative pour ceci :
common_id = ANY
(
SELECT common_id
FROM table1 t1
)
Le résultat de cette condition est un produit booléen de toutes les comparaisons de la liste. Bien sûr, un seul NULL
la valeur donne le NULL
result qui rend le résultat entier NULL
aussi.
Nous ne pouvons jamais dire avec certitude que common_id
n'est égal à aucun élément de cette liste, car au moins une des valeurs est NULL
.
Supposons que nous ayons ces données :
common
--
1
3
table1
--
NULL
1
2
LEFT JOIN / IS NULL
et NOT EXISTS
renverra 3
, NOT IN
ne renverra rien (car il évaluera toujours soit FALSE
ou NULL
).
En MySQL
, dans le cas d'une colonne non nullable, LEFT JOIN / IS NULL
et NOT IN
sont un peu (plusieurs pour cent) plus efficaces que NOT EXISTS
. Si la colonne est nullable, NOT EXISTS
est le plus efficace (encore une fois, pas beaucoup).
Dans Oracle
, les trois requêtes donnent les mêmes plans (un ANTI JOIN
).
Dans SQL Server
, NOT IN
/ NOT EXISTS
sont plus efficaces, puisque LEFT JOIN / IS NULL
ne peut pas être optimisé pour un ANTI JOIN
par son optimiseur.
Dans PostgreSQL
, LEFT JOIN / IS NULL
et NOT EXISTS
sont plus efficaces que NOT IN
, puisqu'ils sont optimisés pour un Anti Join
, tandis que NOT IN
utilise hashed subplan
(ou même un simple subplan
si la sous-requête est trop grande pour être hachée)