Обновление:
Эти статьи в моем блоге описывают различия между методами более подробно:
Есть три способа сделать такой запрос:
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
не имеет значения nullable, все эти запросы семантически совпадают.
Когда он обнуляем, 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
, в случае столбца без значения NULL, 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
, если подзапрос слишком велик для хэширования)