Какие более эффективные, CTE или временные таблицы?

Что более результативно, CTE или Temporary Tables?

Ответ 1

Я бы сказал, что они разные концепции, но не слишком разные, чтобы сказать "мел и сыр".

  • Временная таблица хороша для повторного использования или для выполнения нескольких обработок для набора данных.

  • CTE может использоваться либо для рецензирования, либо для просто улучшенной читаемости.
    И, подобно функции представления или встроенной таблицы, можно также рассматривать как макрос, который должен быть расширен в основном запросе

  • Таблица temp - это другая таблица с некоторыми правилами вокруг области

Я сохранил procs, где я использую (и табличные переменные тоже)

Ответ 2

Это зависит.

Прежде всего

Что такое выражение общей таблицы?

A (не рекурсивный) 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

Plan 1

Обратите внимание, что в плане выше нет упоминания о 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 строк из 1000 000 случайно сгенерированных значений соответствуют предикату, но дорогостоящее сканирование таблицы происходит 16 раз, чтобы найти их.

enter image description here

Это было бы хорошим кандидатом для материализации промежуточного результата. Эквивалентная перезапись таблицы temp занимает 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 

With Plan

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

В некоторых случаях SQL Server будет использовать катушку для кэширования промежуточного результата, например. CTE и избегать переоценки этого поддерева. Это обсуждается в (мигрированном) элементе Connect Предоставляет подсказку для принудительной промежуточной материализации CTE или производных таблиц. Однако никакие статистические данные не создаются и даже если количество буферизованных строк должно сильно отличаться от оцененного, невозможно, чтобы план выполнения выполнения динамически адаптировался в ответ (по крайней мере, в текущих версиях. Адаптивные планы запросов могут стать возможными в будущее).

Ответ 3

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

Ответ 4

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

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

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

Итак, нет четкого ответа в конце, но лично я бы предпочел CTE над временными таблицами.

Ответ 5

CTE не займет никакого физического пространства. Это просто набор результатов, с которым мы можем использовать join.

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

Область таблицы Temp только в сеансе. EX: Откройте два окна SQL-запросов

create table #temp(empid int,empname varchar)
insert into #temp 
select 101,'xxx'

select * from #temp

Запустить этот запрос в первом окне затем запустите указанный ниже запрос во втором окне, вы можете найти разницу.

select * from #temp

Ответ 6

Итак, запрос, который мне был назначен для оптимизации, был написан двумя CTE на SQL-сервере. Это заняло 28 секунд.

Я потратил две минуты, превратив их в временные таблицы, и запрос занял 3 секунды

Я добавил индекс в таблицу temp в поле, к которому он был присоединен, и получил его до 2 секунд

Три минуты работы, и теперь он работает 12 раз быстрее, удалив CTE. Я лично не буду использовать CTE, если они еще сложнее отлаживать.

Сумасшедшая вещь: CTE использовались только один раз, и все же установка индекса на них оказалась на 50% быстрее.

Ответ 7

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

Например, я создал sprocs, которые возвращаются с результатами больших вычислений за 15 секунд, но преобразуют этот код в CTE и видели, что он работает более 8 минут, чтобы достичь тех же результатов.

Ответ 8

Позднее вечеринке, но...

Среда, в которой я работаю, сильно ограничена, поддерживает некоторые продукты поставщиков и предоставляет услуги с добавленной стоимостью, такие как отчетность. Из-за ограничений политики и контракта я обычно не допускаю роскоши отдельного пространства таблиц/данных и/или возможности создания постоянного кода [он становится немного лучше, в зависимости от приложения].

IOW, я обычно не могу создавать хранимую процедуру или таблицы UDF или temp и т.д. Мне в значительной степени нужно делать все через интерфейс MY-приложений (Crystal Reports - добавлять/связывать таблицы, устанавливать где предложения из w/в CR, и т.д.). Одним из преимуществ экономии SMALL является то, что Crystal позволяет мне использовать COMMANDS (а также SQL-выражения). Некоторые вещи, которые неэффективны благодаря регулярным добавлениям/ссылкам, могут быть выполнены путем определения команды SQL. Я использую CTE через это и получил очень хорошие результаты "удаленно". CTE также помогают в обслуживании отчетов, не требуя разработки кода, передаются администратору базы данных для компиляции, шифрования, передачи, установки и последующего многоуровневого тестирования. Я могу делать CTE через локальный интерфейс.

Нижняя сторона использования CTEs/CR - каждый отчет является отдельным. Каждый CTE должен поддерживаться для каждого отчета. Там, где я могу делать SP и UDF, я могу разработать что-то, что может использоваться несколькими отчетами, требуя только ссылки на SP и параметры передачи, как если бы вы работали над обычной таблицей. CR не очень хорош в обработке параметров в SQL-командах, так что аспект аспекта CR/CTE может отсутствовать. В таких случаях я обычно пытаюсь определить CTE, чтобы вернуть достаточно данных (но не ВСЕ данные), а затем использовать возможности выбора записи в CR для фрагментов и кубиков.

Итак... мой голос за CTE (пока я не получу свое пространство данных).

Ответ 9

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

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

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

Ответ 10

Это действительно открытый вопрос, и все зависит от его использования и типа таблицы temp (переменная таблицы или традиционная таблица).

Традиционная временная таблица хранит данные в временном БД, что замедляет темп-таблицы; однако переменные таблицы этого не делают.

Ответ 11

Я только что протестировал это: CTE и non-CTE (где запрос был напечатан для каждого экземпляра объединения) заняли ~ 31 секунду. CTE сделал код гораздо более удобочитаемым, но сократил его с 241 до 130 строк, что очень приятно. С другой стороны, таблица Temp сократила ее до 132 строк и запустила FIVE SECONDS. Без шуток. все это тестирование было кэшировано - все запросы выполнялись несколько раз раньше.

Ответ 12

Из моего опыта работы в SQL Server я нашел один из сценариев, в которых CTE превзошла таблицу Temp

Мне нужно было использовать DataSet (~ 100000) из сложного запроса только один раз в моей хранимой процедуре.

  • Таблица Temp вызывала накладные расходы на SQL, где моя процедура была (так как Temp Tables являются реальными материализованными таблицами, которые существуют в tempdb и Persist для жизни моей текущей процедуры)

  • С другой стороны, с CTE, CTE Persist только до следующего запрос выполняется. Таким образом, CTE - удобная в памяти структура с ограниченными возможностями Объем. CTE не используют tempdb по умолчанию.

Это один из сценариев, когда CTE могут действительно помочь упростить ваш код и Outperform Temp Table. Я использовал 2 CTE, что-то вроде

WITH CTE1(ID, Name, Display) 
AS (SELECT ID,Name,Display from Table1 where <Some Condition>),
CTE2(ID,Name,<col3>) AS (SELECT ID, Name,<> FROM CTE1 INNER JOIN Table2 <Some Condition>)
SELECT CTE2.ID,CTE2.<col3>
FROM CTE2
GO