Если я хочу найти набор записей в таблице A, но не в таблице B, я могу использовать LEFT OUTER JOIN или NOT EXISTS. Я слышал, что SQL Server ориентирован на ANSI, а в некоторых случаях LEFT OUTER JOINs намного эффективнее, чем NOT EXISTS. Будет ли ANSI JOIN работать лучше в этом случае? и являются ли операторы объединения более эффективными, чем НЕ СУЩЕСТВУЮЩИЕ вообще на SQL Server?
Производительность SQL в LEFT OUTER JOIN vs. NOT EXISTS
Ответ 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
для большинства людей) и продолжайте.
Ответ 4
Ответ 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
запускается в режиме вложенного цикла. При этом он выполняется на основе каждой строки (что, я полагаю, имеет смысл).