Почему соединение SQL выбирает субоптимальный план запроса?

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

Я неоднократно сталкивался с этой проблемой с разными и несвязанными запросами. Следующий запрос занимает много минут:

SELECT <Fields>
FROM <Multiple Tables Joined>
    LEFT JOIN (SELECT <Fields> FROM <Multiple Tables Joined> ) ON <Condition>

Однако, просто добавив подсказку соединения, запрос выполняется за несколько секунд:

SELECT <Fields>
FROM <Multiple Tables Joined>
    LEFT HASH JOIN (SELECT <Fields> FROM <Multiple Tables Joined> ) ON <Condition>

Странно, что тип JOIN, указанный в подсказке, на самом деле не является тем, что улучшает производительность. По-видимому, это связано с тем, что подсказка заставляет оптимизатор выполнять отдельный запрос в отдельности и затем присоединяться. Я вижу такое же улучшение производительности, если я создаю функцию таблицы (не встроенную) для подзапроса. например.

SELECT <Fields>
FROM <Multiple Tables Joined>
    LEFT JOIN dbo.MySubQueryFunction() ON <Condition>

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

Ответы

Ответ 1

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

Это происходит из-за отсутствия статистики по участвующим таблицам.

Ответ 2

Оптимизатор - это алгоритм. Он не является немым или умным, он работает так, как он запрограммирован.

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

В первом случае оптимизатор мог выбрать nested loop. Он переместил условие соединения во внутренний запрос и выполнил внутренний запрос на каждой итерации с помощью дополнительного предиката. Он может не найти подходящего индекса для этого предиката, а full table scan - на каждой итерации.

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

С помощью функции таблицы невозможно вставить условие соединения во внутренний запрос, поэтому он выполняется только один раз.

Ответ 3

Внутри SQL Server 2005: запрос T-SQL отвечает на эти и многие другие вопросы. Один из лучших взглядов под капотом поиска данных T-SQL и обработки глаголов, которые я когда-либо видел. (Нет, я не являюсь автором книги, и я не связан ни с каким автором или авторами книги, или с Microsoft, или с Microsoft Press. Это просто невероятная работа, и различные администраторы баз данных, которые я включил в прошлое пару лет согласны.)