Медленный SQL-запрос из-за внутреннего и левого соединения? - PullRequest
4 голосов
/ 06 сентября 2008

Кто-нибудь может объяснить это поведение или как его обойти?

Если вы выполните этот запрос:

select * 
from TblA
left join freetexttable ( TblB, *, 'query' ) on TblA.ID = [Key]
inner join DifferentDbCatalog.dbo.TblC on TblA.ID = TblC.TblAID

Это будет очень очень очень медленно.

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

Вы можете наблюдать такое же поведение, если вы используете переменную таблицы sql вместо freetexttable.

Проблема производительности возникает всякий раз, когда у вас есть переменная таблицы (или freetexttable) и таблица в другом каталоге базы данных, где одна находится во внутреннем соединении, а другая в левом соединении.

Кто-нибудь знает, почему это медленно или как его ускорить?

Ответы [ 4 ]

7 голосов
/ 06 сентября 2008

Общее правило заключается в том, что OUTER JOIN приводит к увеличению числа строк в наборе результатов на увеличение, , тогда как INNER JOINs приводит к уменьшению количества строк в наборе результатов на . Конечно, существует множество сценариев, где верно и обратное, но скорее всего это сработает, чем нет. Что вы хотите сделать для производительности, так это сохранить размер набора результатов (рабочего набора) как можно меньшим как можно дольше.

Поскольку оба объединения совпадают на первой таблице, изменение порядка не повлияет на точность результатов. Следовательно, вы, вероятно, хотите выполнить ВНУТРЕННЕЕ СОЕДИНЕНИЕ до ЛЕВОГО СОЕДИНЕНИЯ:

SELECT * 
FROM TblA
INNER JOIN DifferentDbCatalog.dbo.TblC on TblA.ID = TblC.TblAID
LEFT JOIN freetexttable ( TblB, *, 'query' ) on TblA.ID = [Key]

На практике оптимизатор запросов должен быть достаточно умен, чтобы компилировать, чтобы использовать более быстрый вариант, независимо от того, какой порядок вы указали для объединений. Однако рекомендуется делать вид, что у вас тупой оптимизатор запросов, и что операции с запросами выполняются по порядку. Это помогает будущим сопровождающим определить потенциальные ошибки или предположения о характере таблиц.

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

3 голосов
/ 06 сентября 2008

Обычно вам нужно включить опцию «Показать фактический план выполнения», а затем внимательно посмотреть на причины замедления. (наведите указатель мыши на каждое объединение, чтобы просмотреть подробности). Вам нужно убедиться, что вы получаете поиск по индексу, а не сканирование таблицы.

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

0 голосов
/ 06 сентября 2008

Помещение freetexttable(TblB, *, 'query') во временную таблицу может помочь, если его вызывали повторно в плане выполнения.

0 голосов
/ 06 сентября 2008

Индексируйте поле, которое вы используете для выполнения объединения.

Хорошее эмпирическое правило - назначить индекс для любых обычно упоминаемых иностранных или ключей-кандидатов .

...