В чем разница между NOT EXISTS и NOT IN против LEFT JOIN, ГДЕ НУЛЬ?
Мне кажется, что вы можете сделать то же самое в SQL-запросе, используя NOT EXISTS, NOT IN или LEFT JOIN WHERE NULL. Например:
SELECT a FROM table1 WHERE a NOT IN (SELECT a FROM table2)
SELECT a FROM table1 WHERE NOT EXISTS (SELECT * FROM table2 WHERE table1.a = table2.a)
SELECT a FROM table1 LEFT JOIN table2 ON table1.a = table2.a WHERE table1.a IS NULL
Я не уверен, правильно ли я понял весь синтаксис, но это общие приемы, которые я видел. Почему я решил бы использовать один над другим? Отличается ли производительность...? Какой из них самый быстрый / самый эффективный? (Если это зависит от реализации, когда я буду использовать каждый из них?)
5 ответов
NOT IN против NOT EXISTS vs. LEFT JOIN / IS NULL: SQL Server
NOT IN против NOT EXISTS vs. LEFT JOIN / IS NULL: PostgreSQL
НЕ В, против НЕ СУЩЕСТВУЕТ, ПРОТИВ ЛЕВНОГО СОЕДИНЕНИЯ / НУЛЬ: Oracle
НЕ В, против НЕ СУЩЕСТВУЕТ, ПРОТИВ ЛЕВОГО СОЕДИНЕНИЯ / НУЛЬ: MySQL
В двух словах:
NOT IN
немного отличается: он никогда не совпадает, если есть только один NULL
в списке.
В
MySQL
,NOT EXISTS
немного менее эффективенВ
SQL Server
,LEFT JOIN / IS NULL
менее эффективенВ
PostgreSQL
,NOT IN
менее эффективенВ
Oracle
Все три метода одинаковы.
Если база данных хороша для оптимизации запроса, два первых будут преобразованы во что-то близкое к третьему.
Для простых ситуаций, подобных тем, о которых вы спрашиваете, различий не должно быть или почти не должно быть, поскольку все они будут выполняться как объединения. В более сложных запросах база данных может быть не в состоянии сделать соединение из not in
а также not exists
queryes. В этом случае запросы станут намного медленнее. С другой стороны, объединение может также работать плохо, если нет индекса, который можно использовать, так что если вы используете объединение, это еще не значит, что вы в безопасности. Вам нужно будет изучить план выполнения запроса, чтобы определить, могут ли быть проблемы с производительностью.
Предполагая, что вы избегаете пустых значений, они являются всеми способами написания анти-объединения с использованием стандартного SQL.
Очевидным упущением является эквивалент использования EXCEPT
:
SELECT a FROM table1
EXCEPT
SELECT a FROM table2
Обратите внимание, что в Oracle вам нужно использовать MINUS
оператор (возможно, лучшее имя):
SELECT a FROM table1
MINUS
SELECT a FROM table2
Говоря о проприетарном синтаксисе, могут быть и нестандартные эквиваленты, которые стоит изучить в зависимости от используемого вами продукта, например OUTER APPLY
в SQL Server (что-то вроде):
SELECT t1.a
FROM table1 t1
OUTER APPLY
(
SELECT t2.a
FROM table2 t2
WHERE t2.a = t1.a
) AS dt1
WHERE dt1.a IS NULL;
С точки зрения производительности всегда избегайте использования обратных ключевых слов, таких как NOT IN, NOT EXISTS, ... Потому что для проверки обратных элементов СУБД необходимо просмотреть все доступные и отбросить обратный выбор.
Когда нужно вставить данные в таблицу с многопольным первичным ключом, учтите, что будет намного быстрее (я пытался в Access, но я думаю, в любой базе данных) не проверять, что "не существует записей с" такими "значениями в таблице", - скорее просто вставьте в таблицу, и лишние записи (по ключу) не будут вставлены дважды.