Aktualizacja:
Te artykuły na moim blogu bardziej szczegółowo opisują różnice między metodami:
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
)
Gdy table1.common_id
nie dopuszcza wartości null, wszystkie te zapytania są semantycznie takie same.
Kiedy jest dopuszczalna wartość null, NOT IN
jest różna, ponieważ IN
(i dlatego NOT IN
) zwraca, 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ę tego:
common_id = ANY
(
SELECT common_id
FROM table1 t1
)
Wynik tego warunku jest logicznym iloczynem wszystkich porównań na liście. Oczywiście pojedyncza NULL
wartość daje NULL
wynik, który renderuje również cały wynik NULL
.
Nigdy nie możemy z całą pewnością stwierdzić, że common_id
nie jest to coś 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
nie zwróci nic (ponieważ zawsze będzie zwracać wartość albo FALSE
lub NULL
).
W MySQL
przypadku, gdy kolumna nie dopuszcza wartości null LEFT JOIN / IS NULL
i NOT IN
są nieco (kilka procent) wydajniejsze niż NOT EXISTS
. Jeśli kolumna dopuszcza wartość null, NOT EXISTS
jest najbardziej wydajna (znowu niewiele).
W programie Oracle
wszystkie trzy zapytania dają takie same plany (an ANTI JOIN
).
W SQL Server
, NOT IN
/ NOT EXISTS
są bardziej wydajne, ponieważ LEFT JOIN / IS NULL
nie mogą być zoptymalizowane do an ANTI JOIN
przez jego optymalizator.
W PostgreSQL
, LEFT JOIN / IS NULL
i NOT EXISTS
są bardziej skuteczne niż NOT IN
sinus są zoptymalizowane Anti Join
, podczas NOT IN
zastosowania hashed subplan
(lub nawet gładkie subplan
czy podkwerendę jest zbyt duża, aby hash)