Медленный 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) и таблица в другом каталоге базы данных, где одна находится во внутреннем соединении, а другая - в левом.
Кто-нибудь знает, почему это медленно, или как его ускорить?
4 ответа
Общее правило состоит в том, что OUTER JOINs приводит к увеличению числа строк в наборе результатов , в то время как INNER JOIN приводит к уменьшению количества строк в наборе результатов . Конечно, существует множество сценариев, в которых верно и обратное, но скорее всего это сработает, чем нет. Что вы хотите сделать для производительности, так это сохранить размер набора результатов (рабочего набора) как можно меньшим как можно дольше.
Поскольку оба объединения совпадают в первой таблице, изменение порядка не повлияет на точность результатов. Следовательно, вы, вероятно, захотите выполнить ВНУТРЕННЕЕ СОЕДИНЕНИЕ до ЛЕВОГО СОЕДИНЕНИЯ
SELECT *
FROM TblA
INNER JOIN DifferentDbCatalog.dbo.TblC on TblA.ID = TblC.TblAID
LEFT JOIN freetexttable ( TblB, *, 'query' ) on TblA.ID = [Key]
На практике оптимизатор запросов должен быть достаточно умен, чтобы компилировать, чтобы использовать более быстрый вариант, независимо от того, какой порядок вы указали для объединений. Однако рекомендуется делать вид, что у вас тупой оптимизатор запросов, и что операции с запросами выполняются по порядку. Это помогает будущим сопровождающим определить потенциальные ошибки или предположения о характере таблиц.
Поскольку оптимизатор должен переписывать что-то, этого, вероятно, недостаточно для того, чтобы полностью объяснить поведение, которое вы видите, поэтому вам все еще нужно изучить план выполнения, используемый для каждого запроса, и, возможно, добавить индекс, как предлагалось ранее., Это все еще хороший принцип для изучения.
Обычно вы должны включить опцию "Показать фактический план выполнения", а затем внимательно посмотреть, что вызывает замедление. (наведите указатель мыши на каждое объединение, чтобы увидеть подробности). Вам нужно убедиться, что вы получаете поиск по индексу, а не сканирование таблицы.
Я хотел бы предположить, что происходит то, что SQL вынужден вытягивать все из одной таблицы в память для выполнения одного из соединений. Иногда изменение порядка, в котором вы присоединяетесь к столам, также может помочь.
Ввод freetexttable(TblB, *, 'query')
во временную таблицу может помочь, если она вызывается повторно в плане выполнения.
Индексируйте поле, которое вы используете для выполнения объединения.
Хорошее практическое правило - назначить индекс для любых обычно упоминаемых внешних или потенциальных ключей.