Производительность SQL в LEFT OUTER JOIN vs. NOT EXISTS

Если я хочу найти набор записей в таблице A, но не в таблице B, я могу использовать LEFT OUTER JOIN или NOT EXISTS. Я слышал, что SQL Server ориентирован на ANSI, а в некоторых случаях LEFT OUTER JOINs намного эффективнее, чем NOT EXISTS. Будет ли ANSI JOIN работать лучше в этом случае? и являются ли операторы объединения более эффективными, чем НЕ СУЩЕСТВУЮЩИЕ вообще на SQL Server?

Ответ 1

Ссылка Joe - хорошая отправная точка. Quassnoi также охватывает это.

В общем случае, если ваши поля правильно проиндексированы, или если вы хотите отфильтровать больше записей (т.е. иметь много строк EXIST в подзапросе) NOT EXISTS будет работать лучше.

EXISTS и NOT EXISTS оба коротких замыкания - как только запись соответствует критериям, которые она включает или отфильтровывает, и оптимизатор переходит к следующей записи.

LEFT JOIN присоединяется к ВСЕ RECORDS независимо от того, совпадают они или нет, а затем отфильтровывает все несоответствующие записи. Если ваши таблицы большие и/или у вас несколько критериев JOIN, это может быть очень ресурсоемким.

Обычно я стараюсь использовать NOT EXISTS и EXISTS, где это возможно. Для SQL Server IN и NOT IN являются семантически эквивалентными и могут быть проще записать. Это одни из единственных операторов, которые вы найдете в SQL Server, которые гарантируют короткое замыкание.

Ответ 2

Лучшее обсуждение, которое я прочитал в этом разделе для SQL Server, здесь.

Ответ 3

Лично я думаю, что этот человек становится старым, "Он зависеть". Я видел примеры, когда каждый метод превосходил другой.

Лучше всего проверить и посмотреть, кто работает лучше. Если это ситуация, когда таблицы всегда будут маленькими, а производительность не так важна, я просто зайду в зависимости от того, что вам лучше (обычно это NOT EXISTS для большинства людей) и продолжайте.

Ответ 5

Мне было интересно, как мы можем использовать индекс в таблице, которую мы удаляем в этих случаях, которые описывает OP.

Скажем, что у нас есть:

 table EMPLOYEE (emp_id int, name varchar) 
and
 table EMPLOYEE_LOCATION (emp_id int, loc_id int)

В моем примере в реальном мире мои таблицы намного шире и содержат 1 миллион + строк, я упростил схему, например, цель.

Если я хочу удалить строки из EMPLOYEE_LOCATION, которые не имеют соответствующего emp_id в EMPLOYEE, я, очевидно, могу использовать левую внешнюю технику или NOT IN, но мне было интересно...

Если обе таблицы имеют индексы с ведущим столбцом emp_id, то стоит ли их использовать?

Возможно, я мог бы вытащить emp_id из EMPLOYEE, emp_id из EMPLOYEE_LOCATION в временную таблицу и получить emp_id из временных таблиц, которые я хочу удалить.

Затем я мог бы объединить эти emp_id и фактически использовать индекс так:

loop for each emp_id X to delete -- (this would be a cursor)
 DELETE EMPLOYEE_LOCATION WHERE emp_id = X

Я знаю, что есть накладные расходы с помощью курсора, но в моем реальном примере я имею дело с огромными таблицами, поэтому я думаю, что явное использование индекса желательно.

Ответ 6

Отвечать на dba.stackexchange

Исключением я заметил, что NOT EXISTS является превосходным (хотя и незначительно) до LEFT JOIN ... WHERE IS NULL при использовании Linked Servers.

Изучая планы выполнения, кажется, что оператор NOT EXISTS запускается в режиме вложенного цикла. При этом он выполняется на основе каждой строки (что, я полагаю, имеет смысл).

Пример плана выполнения, демонстрирующий это поведение: введите описание изображения здесь