2010-03-05 3 views
25

У нас есть запрос ниже. Использование соединения LEFT OUTER занимает 9 секунд. Изменение LEFT OUTER на LEFT INNER уменьшает время выполнения до 2 секунд, и возвращается то число. Поскольку обрабатывается одинаковое количество строк из таблицы dbo.Accepts, независимо от типа соединения, почему внешний элемент займет 3 раза?LEFT INNER JOIN против LEFT OUTER JOIN - Почему OUTER занимает больше времени?

SELECT CONVERT(varchar, a.ReadTime, 101) as ReadDate, 
     a.SubID, 
     a.PlantID, 
     a.Unit as UnitID, 
     a.SubAssembly, 
     m.Lot 
    FROM dbo.Accepts a WITH (NOLOCK) 
LEFT OUTER Join dbo.Marker m WITH (NOLOCK) ON m.SubID = a.SubID 
WHERE a.LastModifiedTime BETWEEN @LastModifiedTimeStart AND @LastModifiedTimeEnd 
    AND a.SubAssembly = '400' 
+23

Я не знал, что существует такая вещь, как «ВЛЕВО-ВЗАИМОДЕЙСТВИЕ». Что оно делает? –

+5

Я подозреваю, что 'LEFT' из' LEFT INNER' получает изъяты, и это просто «INNER JOIN». –

+1

Использование SQL Server 2005 я не могу запустить запрос, используя 'LEFT INNER JOIN' - я получаю« Неправильный синтаксис рядом с ключевым словом «INNER». Какую версию SQL Server вы используете? Если 2005+, вы работаете на пониженном уровне совместимости? –

ответ

35

Тот факт, что такое же количество строк возвращается загробная Фактически, оптимизатор запросов не может заранее знать, что каждая строка в Допускает имеет соответствующей строки в маркер, может это?

Если вы присоединитесь к двум таблицам A и B, скажем, что A имеет 1 миллион строк, а B имеет 1 строку. Если вы говорите A LEFT INNER JOIN B, это означает, что только строки, соответствующие , могут быть получены как A, так и B, поэтому план запроса может сначала сканировать B, а затем использовать индекс для сканирования диапазона в A и, возможно, вернуть 10 строк. Но если вы скажете A LEFT OUTER JOIN B, то не менее все строки в A должны быть возвращены, поэтому план должен сканировать все в A независимо от того, что он находит в B.Используя соединение OUTER, вы устраняете одну возможную оптимизацию.

Если вы делаете знаете, что каждая строка в Accepts будет иметь совпадение в Marker, то почему бы не объявить внешний ключ для принудительного применения этого? Оптимизатор увидит ограничение, и если он будет доверен, он учтет его в плане.

+10

Подождите ... Нет такой вещи, как «ЛЕВАЯ ВХОДНАЯ ВСТРЕЧА». Это либо «LEFT JOIN», либо «LEFT OUTER JOIN». «INNER» уже означает, что это пересечение, и пересечение может быть только одним. Вот почему есть ключевое слово «OUTER». Не знаю, как этот ответ получил 19 голосов ... Если я не упустил что-то совершенно новое здесь. –

+2

@NicholasPufal: В качестве синтаксиса SQL вы правы, ['INNER' не имеет' LEFT' или 'RIGHT'] (http://msdn.microsoft.com/en-us/library/ms177634.aspx). 'LEFT' или' LEFT OUTER' означает то же самое, 'OUTER' является необязательным токеном. Есть много комментариев к ОП, которые уже охватывают это. Но я прекрасно понимал, что означает Рэнди, и, я думаю, он понял, что я имею в виду. –

+0

Извините. Я снова прочитал ваш ответ, и вы просто делаете свою мысль на основе слов автора. Виноват. Я понял, что ваш ответ совершенно другой. –

28

1) в окне запроса в SQL Server Management Studio, выполните команду:

SET SHOWPLAN_ALL ON

2) запустить ваш медленный запрос

3) запрос не будет работать, но план выполнения будет возвращен. хранить этот вывод

4) запустить быструю версию запроса

5) Ваш запрос не будет работать, но план выполнения будет возвращен. хранить этот выход

6) сравнить выход медленной версии запроса с выходом версии быстрого запроса.

7) если вы все еще не знаете, почему один медленнее, отправьте оба выхода в свой вопрос (отредактируйте его), и кто-то здесь может помочь оттуда.

+2

'SET SHOWPLAN_ALL ON' - моя новая любимая команда на сегодня !!! –

+2

Я думаю, что это больше «научить человека ловить рыбу ...» ответ. Активировано для этой команды, которую я собираюсь заставить всех моих разработчиков учиться. –

+0

Код ошибки: 1193. Неизвестная системная переменная 'SHOWPLAN_ALL'. Как я должен запустить эту команду – makkasi

2

Подождите - вы на самом деле означает, что «такое же количество строк ... в настоящее время обрабатываются » или что «такое же количество строк в настоящее время возвращается»? В общем случае внешнее объединение обрабатывало бы еще много строк, в том числе те, для которых нет совпадений, даже если они возвращают одинаковое количество записей.

+1

Извините, я был немного небрежен. Такое же количество строк возвращается. –

6

Это потому, что LEFT OUTER Join выполняет больше работы, чем INNER Join, перед отправкой результатов.

Inner Join ищет все записи, где оператор ON является истинным (поэтому, когда он создает новую таблицу, он помещает только записи, соответствующие m.SubID = a.SubID). Затем он сравнивает эти результаты с вашим предложением WHERE (ваше последнее измененное время).

The Left Outer Join ... Принимает все записи в вашем первом столе. Если инструкция ON неверна (m.SubID не равен a.SubID), она просто NULLS значения во втором столбце таблицы для этого набора записей.

Причина, по которой вы получаете одинаковое количество результатов в конце, вероятно, является совпадением из-за предложения WHERE, которое происходит ПОСЛЕ всех копий записей.

Join (SQL) Wikipedia