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