Mettre à jour:
Ces articles de mon blog décrivent plus en détail les différences entre les méthodes:
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
)
Quand table1.common_id
n'est pas nullable, toutes ces requêtes sont sémantiquement identiques.
Quand il est nullable, NOT IN
est différent, puisque IN
(et, par conséquent, NOT IN
) retourne NULL
quand une valeur ne correspond à rien dans une liste contenant un NULL
.
Cela peut être déroutant 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 dans la liste. Bien sûr, une seule NULL
valeur donne le NULL
résultat qui rend également le résultat entier NULL
.
Nous ne pouvons jamais dire avec certitude que ce common_id
n'est égal à rien de cette liste, car au moins une des valeurs l'est NULL
.
Supposons que nous ayons ces données:
common
--
1
3
table1
--
NULL
1
2
LEFT JOIN / IS NULL
et NOT EXISTS
retournera 3
, NOT IN
ne retournera rien (car il sera toujours évalué à l'un FALSE
ou l' autre NULL
).
Dans MySQL
, en cas de colonne non nullable, LEFT JOIN / IS NULL
et NOT IN
sont un peu plus efficaces (plusieurs pour cent) que NOT EXISTS
. Si la colonne est nullable, NOT EXISTS
c'est le plus efficace (encore une fois, pas beaucoup).
Dans Oracle
, les trois requêtes génèrent les mêmes plans (an ANTI JOIN
).
Dans SQL Server
, NOT IN
/ NOT EXISTS
sont plus efficaces, car LEFT JOIN / IS NULL
ne peuvent pas être optimisés à un ANTI JOIN
par son optimiseur.
Dans PostgreSQL
, LEFT JOIN / IS NULL
et NOT EXISTS
sont plus efficaces que NOT IN
, sine, ils sont optimisés pour un Anti Join
, while NOT IN
uses hashed subplan
(ou même un plain subplan
si la sous-requête est trop grande pour le hachage)