Ваш вопрос показывает, что вы уступили некоторым распространенным заблуждениям, связанным с табличными переменными и временными таблицами.
Я написал довольно обширный ответ на сайте DBA, в котором рассматриваются различия между двумя типами объектов. Это также отвечает на ваш вопрос о дисках и памяти (я не видел существенной разницы в поведении между ними).
Что касается вопроса в заголовке о том, когда использовать переменную таблицы против локальной временной таблицы, у вас не всегда есть выбор. Например, в функциях можно использовать только переменную таблицы, и если вам нужно записать данные в таблицу в дочерней области, то #temp
подойдет только таблица (табличные параметры разрешают доступ только для чтения). ).
Там, где у вас есть выбор, ниже приведены некоторые предложения (хотя самый надежный метод - просто протестировать оба варианта с вашей конкретной рабочей нагрузкой).
Если вам нужен индекс, который нельзя создать для табличной переменной, тогда вам, конечно, понадобится #temporary
таблица. Детали этого зависят от версии, однако. Для SQL Server 2012 и ниже единственными индексами, которые могли быть созданы для табличных переменных, были те, которые неявно создавались с помощью ограничения UNIQUE
или PRIMARY KEY
. SQL Server 2014 ввел синтаксис встроенного индекса для подмножества параметров, доступных в CREATE INDEX
. С тех пор это было расширено, чтобы позволить фильтровать условия индекса. Однако индексы с INCLUDE
столбцами -d или индексами columnstore все еще невозможно создать для переменных таблицы.
Если вы будете многократно добавлять и удалять большое количество строк в таблице, используйте #temporary
таблицу. Это поддерживает TRUNCATE
(что более эффективно, чем DELETE
для больших таблиц), и дополнительно последующие вставки после a TRUNCATE
могут иметь лучшую производительность, чем те, которые следуют за a, DELETE
как показано здесь .
- Если вы будете удалять или обновлять большое количество строк, тогда временная таблица может работать намного лучше, чем переменная таблицы - если она может использовать совместное использование набора строк (например, см. «Эффекты совместного использования набора строк» ниже).
- Если оптимальный план с использованием таблицы будет зависеть от данных, используйте
#temporary
таблицу. Это поддерживает создание статистики, которая позволяет динамически перекомпилировать план в соответствии с данными (хотя для кэшированных временных таблиц в хранимых процедурах поведение перекомпиляции необходимо понимать отдельно).
- Если оптимальный план для запроса, использующего таблицу, вряд ли когда-либо изменится, вы можете рассмотреть возможность использования табличной переменной, чтобы пропустить накладные расходы на создание и перекомпиляцию статистики (возможно, потребуются подсказки, чтобы исправить план, который вы хотите).
- Если источником данных, вставленных в таблицу, являются потенциально дорогие
SELECT
оператор, то учтите, что использование табличной переменной заблокирует возможность этого при использовании параллельного плана.
- Если вам нужны данные в таблице, чтобы пережить откат внешней пользовательской транзакции, используйте переменную таблицы. Возможным вариантом использования этого может быть регистрация хода выполнения различных шагов в длинном пакете SQL.
- При использовании
#temp
таблицы внутри пользовательской блокировки транзакции могут удерживаться дольше, чем для табличных переменных (возможно, до конца транзакции или конца оператора в зависимости от типа блокировки и уровня изоляции), а также это может предотвратить усечение журнала tempdb
транзакций до тех пор, пока Пользовательская транзакция заканчивается. Так что это может способствовать использованию табличных переменных.
- В хранимых подпрограммах можно кэшировать как переменные таблицы, так и временные таблицы. Содержание метаданных для кэшированных табличных переменных меньше, чем для
#temporary
таблиц. Боб Уорд указывает в своей tempdb
презентации, что это может вызвать дополнительную конкуренцию системным таблицам в условиях высокого параллелизма. Кроме того, при работе с небольшими объемами данных это может существенно повлиять на производительность .
Эффекты совместного использования набора строк
DECLARE @T TABLE(id INT PRIMARY KEY, Flag BIT);
CREATE TABLE #T (id INT PRIMARY KEY, Flag BIT);
INSERT INTO @T
output inserted.* into #T
SELECT TOP 1000000 ROW_NUMBER() OVER (ORDER BY @@SPID), 0
FROM master..spt_values v1, master..spt_values v2
SET STATISTICS TIME ON
/*CPU time = 7016 ms, elapsed time = 7860 ms.*/
UPDATE @T SET Flag=1;
/*CPU time = 6234 ms, elapsed time = 7236 ms.*/
DELETE FROM @T
/* CPU time = 828 ms, elapsed time = 1120 ms.*/
UPDATE #T SET Flag=1;
/*CPU time = 672 ms, elapsed time = 980 ms.*/
DELETE FROM #T
DROP TABLE #T
tempDB
- это «в памяти» - это миф. Также: переменные таблицы всегда будут считаться оптимизатором запросов для хранения ровно одной строки - если у вас их намного больше, это может привести к серьезным неудачным планам выполнения.