Aktualizacja:
Te artykuły na moim blogu bardziej szczegółowo opisują różnice między metodami:
NOT IN
w porównaniu zNOT EXISTS
aLEFT JOIN / IS NULL
:SQL Server
NOT IN
w porównaniu zNOT EXISTS
aLEFT JOIN / IS NULL
:PostgreSQL
NOT IN
w porównaniu zNOT EXISTS
aLEFT JOIN / IS NULL
:Oracle
NOT IN
w porównaniu zNOT EXISTS
aLEFT JOIN / IS NULL
:MySQL
Takie zapytanie można wykonać na trzy sposoby:
-
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 )
Kiedy table1.common_id
nie jest nullable, wszystkie te zapytania są semantycznie takie same.
Gdy jest nullable, NOT IN
jest inny, ponieważ IN
(i dlatego NOT IN
) zwróć NULL
gdy wartość nie pasuje do niczego na liście zawierającej NULL
.
Może to być mylące, ale może stać się bardziej oczywiste, jeśli przypomnimy sobie alternatywną składnię:
common_id = ANY
(
SELECT common_id
FROM table1 t1
)
Wynik tego warunku jest iloczynem logicznym wszystkich porównań na liście. Oczywiście pojedynczy NULL
wartość zwraca NULL
wynik, który renderuje cały wynik NULL
też.
Nigdy nie możemy jednoznacznie stwierdzić, że common_id
nie jest równa niczemu z tej listy, ponieważ przynajmniej jedna z wartości to NULL
.
Załóżmy, że mamy te dane:
common
--
1
3
table1
--
NULL
1
2
LEFT JOIN / IS NULL
i NOT EXISTS
zwróci 3
, NOT IN
zwróci nic (ponieważ zawsze będzie oceniane jako FALSE
lub NULL
).
W MySQL
, w przypadku kolumny nie dopuszczającej wartości null, LEFT JOIN / IS NULL
i NOT IN
są trochę (kilka procent) bardziej wydajne niż NOT EXISTS
. Jeśli kolumna dopuszcza wartość null, NOT EXISTS
jest najbardziej wydajny (ponownie, niewiele).
W Oracle
, wszystkie trzy zapytania dają te same plany (ANTI JOIN
).
W SQL Server
, NOT IN
/ NOT EXISTS
są bardziej wydajne, ponieważ LEFT JOIN / IS NULL
nie można zoptymalizować do ANTI JOIN
przez jego optymalizator.
W PostgreSQL
, LEFT JOIN / IS NULL
i NOT EXISTS
są bardziej wydajne niż NOT IN
, ponieważ są zoptymalizowane pod kątem Anti Join
, podczas gdy NOT IN
używa hashed subplan
(lub nawet zwykły subplan
jeśli podzapytanie jest zbyt duże do haszowania)