SQL 2005 CTE против таблицы TEMP Производительность при использовании в соединениях других таблиц - PullRequest
12 голосов
/ 07 октября 2009

У меня сложный запрос, который мне нужно использовать в последующем запросе (на самом деле, оператор update). Я пробовал использовать CTE и временную таблицу. Производительность при использовании CTE ужасна по сравнению с подходом к временным таблицам. Это что-то вроде 15 секунд против миллисекунд. Чтобы упростить тест вместо того, чтобы присоединять таблицу CTE / Temp в последующем запросе, я просто выбрал * из нее. В этом случае они выполняют то же самое.

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

Мой вопрос заключается в том, почему план запроса для создания и заполнения CTE изменяется в зависимости от того, как он впоследствии используется, а временная таблица - нет. Кроме того, в каких случаях CTE даст лучшую производительность, чем временная таблица?

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

Спасибо

Ответы [ 4 ]

13 голосов
/ 07 октября 2009

CTE это просто псевдоним для запроса.

Он может (или не может) перезапускаться каждый раз, когда используется.

Нет чистого способа заставить CTE материализоваться в SQL Server (как у Oracle /*+ MATERIALIZE */), и вы должны делать такие грязные трюки, как это:

CTE может улучшить производительность, если используется в планах, требующих только одну оценку (например, HASH JOIN, MERGE JOIN и т. Д.).

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

9 голосов
/ 07 октября 2009

Вы задаете сложный вопрос, поэтому вы получаете сложный ответ: это зависит. (Я ненавижу этот ответ).

Серьезно, однако, это связано с тем, как оптимизатор выбирает план данных (который вы уже знали); временная таблица или переменная подобна постоянной структуре в том плане, что план выполнения будет сначала выполнять операцию, связанную с заполнением этой структуры, а затем использовать эту структуру в последующих операциях. CTE НЕ является временной таблицей; использование CTE не рассчитывается до тех пор, пока оно не будет использовано последующими операциями, и поэтому использование влияет на оптимизацию плана.

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

2 голосов
/ 07 октября 2009

Я считаю, что обычно повторное CTE не дает никаких улучшений производительности.

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

Вместо CTE я часто использую встроенные TVF (которые могут содержать CTE), что обеспечивает правильное повторное использование, и ничем не лучше или хуже, чем CTE в моих SP.

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

В этом случае я смотрю на ручное хранение промежуточных результатов, гарантируя, что они правильно проиндексированы, и разбивая процесс на несколько SP, и добавляя WITH RECOMPILE, чтобы у последующих SP были планы, подходящие для данных, которыми они являются собираюсь оперировать.

1 голос
/ 30 октября 2009

Я попытался создать CTE с простым выбранным с фильтром из большой таблицы Затем 3 раза подверили его.

После этого проделайте то же самое с временными таблицами.

Результат составлял 70% времени для CTE -30% времени для временной таблицы. Так что временная таблица лучше для этого решения.

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

...