SQL Server CTE, упомянутый в self, присоединяется медленно - PullRequest
8 голосов
/ 16 июня 2010

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

Затем я ссылаюсь на этот CTE в 4 самостоятельных соединениях слева, чтобы построить промежуточные итоги, используя разныеКритерии.

Запрос довольно сложный, но вот его упрощенная псевдо-версия

WITH DataCTE as
(
     SELECT [columns] FROM table
                      INNER JOIN table2
                      ON [...]

                      INNER JOIN table3
                      ON [...]

                      LEFT JOIN table3
                      ON [...]
)
SELECT [aggregates_columns of each subset] FROM DataCTE Main
LEFT JOIN DataCTE BananasSubset
               ON [...] 
             AND Product = 'Bananas'
             AND Quality = 100
LEFT JOIN DataCTE DamagedBananasSubset
               ON [...]
             AND Product = 'Bananas'
             AND Quality < 20
LEFT JOIN DataCTE MangosSubset
               ON [...]
GROUP BY [

У меня такое ощущение, что SQL Server запутывается и вызывает CTE для каждого самостоятельного соединениячто кажется подтвержденным, глядя на план выполнения, хотя я признаюсь, что не был экспертом в их чтении.

Я бы предположил, что SQL Server достаточно умен, чтобы выполнять извлечение данных из CTE только один раз, скореечем сделать это несколько раз.

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

Версия со ссылкой на версию CTE занимает 40 секунд.Версия, ссылающаяся на временную таблицу, занимает от 1 до 2 секунд.

Почему SQL Server не настолько умен, чтобы сохранять результаты CTE в памяти?

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

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

Были ли у кого-то из вас такие проблемы с производительностью в CTE, и если да, то как вы их отсортировали?

Спасибо,

Харлос

1 Ответ

6 голосов
/ 16 июня 2010

Я считаю, что результаты CTE извлекаются каждый раз.С временной таблицей результаты сохраняются до тех пор, пока она не будет удалена.Казалось бы, это объясняет прирост производительности, который вы видели при переключении на временную таблицу.

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

Ссылки по теме:

Цитата из последней ссылки:

Базовый запрос CTE будет вызываться каждый раз, когда на него ссылаются в следующем сразу же запросе.

Я бы сказал, пойти с временной таблицей.К сожалению, элегантный не всегда лучшее решение.

ОБНОВЛЕНИЕ:

Хммм, что усложняет ситуацию.Мне трудно сказать, не глядя на всю вашу среду.

Некоторые мысли:

  • можете ли вы использовать хранимую процедуру вместо UDF (вместо этого, не изнутри)?
  • Это может быть невозможно, но если вы можете удалить left join из вашего CTE, вы можете переместить его в индексированное представление.Если вы можете сделать это, вы можете увидеть прирост производительности даже по сравнению с временной таблицей.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...