Медленный SQL-запрос из-за внутреннего и левого соединения?

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

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

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) и таблица в другом каталоге базы данных, где одна находится во внутреннем соединении, а другая — в левом соединении.

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


person Kevin Berridge    schedule 05.09.2008    source источник
comment
Как вы это решили? У меня такой же сценарий.   -  person Kiya    schedule 13.11.2019


Ответы (4)


Общее эмпирическое правило заключается в том, что ВНЕШНЕЕ СОЕДИНЕНИЕ вызывает увеличение количества строк в результирующем наборе, а ВНУТРЕННЕЕ СОЕДИНЕНИЕ вызывает уменьшение количества строк в результирующем наборе. Конечно, есть множество сценариев, в которых верно и обратное, но скорее всего, это сработает именно так, а не иначе. Что вы хотите сделать для повышения производительности, так это сохранить размер результирующего набора (рабочего набора) как можно меньшим и как можно дольше.

Поскольку оба объединения совпадают в первой таблице, изменение порядка не повлияет на точность результатов. Поэтому вы, вероятно, захотите выполнить INNER JOIN перед LEFT JOIN:

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

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

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

person Joel Coehoorn    schedule 06.09.2008

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

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

person The How-To Geek    schedule 06.09.2008

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

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

person Community    schedule 06.09.2008

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

person Eugene Yokota    schedule 06.09.2008