Актуализация:
Тези статии в моя блог описват разликите между методите по-подробно:
NOT IN
срещуNOT EXISTS
срещуLEFT JOIN / IS NULL
:SQL Server
NOT IN
срещуNOT EXISTS
срещуLEFT JOIN / IS NULL
:PostgreSQL
NOT IN
срещуNOT EXISTS
срещуLEFT JOIN / IS NULL
:Oracle
NOT IN
срещуNOT EXISTS
срещуLEFT JOIN / IS NULL
:MySQL
Има три начина да направите такава заявка:
-
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 )
Когато table1.common_id
не е нула, всички тези заявки са семантично еднакви.
Когато е нула, NOT IN
е различно, тъй като IN
(и следователно NOT IN
) върне NULL
когато стойност не съвпада с нищо в списък, съдържащ NULL
.
Това може да е объркващо, но може да стане по-очевидно, ако си припомним алтернативния синтаксис за това:
common_id = ANY
(
SELECT common_id
FROM table1 t1
)
Резултатът от това условие е булев продукт на всички сравнения в списъка. Разбира се, един единствен NULL
стойност дава NULL
резултат, който изобразява целия резултат NULL
също.
Никога не можем да кажем определено, че common_id
не е равно на нищо от този списък, тъй като поне една от стойностите е NULL
.
Да предположим, че имаме следните данни:
common
--
1
3
table1
--
NULL
1
2
LEFT JOIN / IS NULL
и NOT EXISTS
ще върне 3
, NOT IN
няма да върне нищо (тъй като винаги ще се оценява на FALSE
или NULL
).
В MySQL
, в случай на колона без нула, LEFT JOIN / IS NULL
и NOT IN
са малко (няколко процента) по-ефективни от NOT EXISTS
. Ако колоната е нула, NOT EXISTS
е най-ефективният (отново не много).
В Oracle
, и трите заявки дават едни и същи планове (ANTI JOIN
).
В SQL Server
, NOT IN
/ NOT EXISTS
са по-ефективни, тъй като LEFT JOIN / IS NULL
не може да бъде оптимизиран за ANTI JOIN
от неговия оптимизатор.
В PostgreSQL
, LEFT JOIN / IS NULL
и NOT EXISTS
са по-ефективни от NOT IN
, тъй като те са оптимизирани за Anti Join
, докато NOT IN
използва hashed subplan
(или дори обикновен subplan
ако подзаявката е твърде голяма за хеширане)