Актуализация:
Тези статии в моя блог описват разликите между методите по-подробно:
NOT INсрещуNOT EXISTSсрещуLEFT JOIN / IS NULL:SQL ServerNOT INсрещуNOT EXISTSсрещуLEFT JOIN / IS NULL:PostgreSQLNOT INсрещуNOT EXISTSсрещуLEFT JOIN / IS NULL:OracleNOT 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 ако подзаявката е твърде голяма за хеширане)