Это зависит.
Прежде всего
Что такое общее табличное выражение?
(нерекурсивный) CTE обрабатывается очень похоже на другие конструкции, которые также могут использоваться как выражения встроенных таблиц в SQL Server. Производные таблицы, представления и встроенные табличные функции. Обратите внимание, что, хотя BOL говорит, что CTE «может рассматриваться как временный набор результатов», это чисто логическое описание. Чаще всего оно не материализуется само по себе.
Что такое временная таблица?
Это набор строк, хранящихся на страницах данных в базе данных tempdb. Страницы данных могут находиться частично или полностью в памяти. Кроме того, временная таблица может быть проиндексирована и иметь статистику столбцов.
Данные испытаний
CREATE TABLE T(A INT IDENTITY PRIMARY KEY, B INT , F CHAR(8000) NULL);
INSERT INTO T(B)
SELECT TOP (1000000) 0 + CAST(NEWID() AS BINARY(4))
FROM master..spt_values v1,
master..spt_values v2;
Пример 1
WITH CTE1 AS
(
SELECT A,
ABS(B) AS Abs_B,
F
FROM T
)
SELECT *
FROM CTE1
WHERE A = 780
Обратите внимание, что в приведенном выше плане нет упоминания о CTE1. Он просто напрямую обращается к базовым таблицам и обрабатывается так же, как
SELECT A,
ABS(B) AS Abs_B,
F
FROM T
WHERE A = 780
Переписывание путем материализации CTE в промежуточную временную таблицу здесь было бы крайне контрпродуктивным.
Материализация определения CTE
SELECT A,
ABS(B) AS Abs_B,
F
FROM T
Может потребоваться копирование около 8 ГБ данных во временную таблицу, тогда все равно придется выбирать из нее.
Пример 2
WITH CTE2
AS (SELECT *,
ROW_NUMBER() OVER (ORDER BY A) AS RN
FROM T
WHERE B % 100000 = 0)
SELECT *
FROM CTE2 T1
CROSS APPLY (SELECT TOP (1) *
FROM CTE2 T2
WHERE T2.A > T1.A
ORDER BY T2.A) CA
Приведенный выше пример занимает около 4 минут на моей машине.
Только 15 строк из 1 000 000 случайно сгенерированных значений соответствуют предикату, но дорогостоящее сканирование таблицы происходит 16 раз, чтобы найти их.
Это было бы хорошим кандидатом для материализации промежуточного результата. Эквивалентная перезапись временной таблицы заняла 25 секунд.
INSERT INTO #T
SELECT *,
ROW_NUMBER() OVER (ORDER BY A) AS RN
FROM T
WHERE B % 100000 = 0
SELECT *
FROM #T T1
CROSS APPLY (SELECT TOP (1) *
FROM #T T2
WHERE T2.A > T1.A
ORDER BY T2.A) CA
Промежуточная материализация части запроса во временную таблицу иногда может быть полезна, даже если она оценивается только один раз - когда она позволяет перекомпилировать оставшуюся часть запроса, используя статистические данные о материализованном результате. Примером такого подхода является статья SQL Cat Когда нужно разбивать сложные запросы .
В некоторых случаях SQL Server будет использовать катушку для кэширования промежуточного результата, например CTE, и избегайте необходимости переоценивать это поддерево. Это обсуждается в (перенастроенном) элементе подключения Предоставить подсказку для принудительной промежуточной материализации CTE или производных таблиц . Однако статистика по этому вопросу не создается, и даже если число строк в буфере должно было сильно отличаться от предполагаемого, невозможно выполнить динамическую адаптацию плана выполнения в процессе выполнения (по крайней мере в текущих версиях. Адаптивные планы запросов могут стать возможными будущее).