Какая разница между NOT EXISTS против NOT IN vs. 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

Я не уверен, правильно ли я получил синтаксис, но это общие методы, которые я видел. Почему я должен использовать один над другим? Отличается ли производительность...? Какой из них самый быстрый/самый эффективный? (Если это зависит от реализации, когда я буду использовать каждый из них?)

Ответ 1

В двух словах:

NOT IN немного отличается: он никогда не совпадает, если в списке есть только один NULL.

  • В MySQL, NOT EXISTS является немного менее эффективным

  • В SQL Server, LEFT JOIN / IS NULL менее эффективен

  • В PostgreSQL, NOT IN менее эффективен

  • В Oracle все три метода одинаковы.

Ответ 2

Если база данных хорошо оптимизирует запрос, два первых будут преобразованы в нечто, близкое к третьему.

Для простых ситуаций, подобных тем, которые вы задаете, разница должна быть небольшой или никакой, поскольку все они будут исполняться как объединения. В более сложных запросах база данных не сможет выполнить соединение с запросами not in и not exists. В этом случае запросы будут намного медленнее. С другой стороны, соединение может также плохо работать, если нет индекса, который можно использовать, поэтому только потому, что вы используете соединение, это не значит, что вы в безопасности. Вам нужно будет изучить план выполнения запроса, чтобы определить, могут ли быть проблемы с производительностью.

Ответ 3

Предполагая, что вы избегаете нулей, все они являются способами написания антисоединения с использованием стандартного 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;

Ответ 4

Когда вам нужно вставить данные в таблицу с помощью первичного ключа с несколькими полями, подумайте, что это будет намного быстрее (я пытался в Access, но я думаю, что в любой базе данных), чтобы не проверять, что "не существует записей с" такими "значениями в table", - скорее просто вставьте в таблицу, а лишние записи (по ключу) не будут вставлены дважды.

Ответ 5

Перспектива производительности всегда избегает использования обратных ключевых слов, таких как NOT IN, NOT EXISTS,... Поскольку для проверки обратных элементов СУБД необходимо выполнить все доступные и отбросить обратный выбор.