Обновить:
В этих статьях моего блога более подробно описаны различия между методами:
Есть три способа выполнить такой запрос:
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не допускает значения NULL, все эти запросы семантически одинаковы.
Когда он допускает значение NULL, 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 вернет (так как всегда будет оцениваться как или ).FALSENULL
В MySQLслучае столбца, не допускающего значения NULL, LEFT JOIN / IS NULLи NOT INони немного (на несколько процентов) более эффективны, чем NOT EXISTS. Если столбец допускает значение NULL, NOT EXISTSэто наиболее эффективно (опять же, не очень).
В Oracleвсе три запроса дают одинаковые планы (an ANTI JOIN).
In 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если подзапрос является слишком большим , чтобы хэш)