Медленный запрос 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.

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

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

Как вы это решили? У меня такой же сценарий.

Kiya 13.11.2019 16:20
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
1
15 881
4

Ответы 4

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

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

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

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

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

Поскольку оба объединения совпадают в первой таблице, изменение порядка не повлияет на точность результатов. Следовательно, вы, вероятно, захотите выполнить 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]

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

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

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

Другие вопросы по теме