Оновлення:
Ці статті в моєму блозі більш детально описують відмінності між методами:
Існує три способи зробити такий запит:
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
коли значення не відповідає нічого в списку, що містить a 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
, все три запити дають однакові плани (AN 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
якщо підзапит занадто великий для хешу)