Когда следует использовать переменную таблицы vs временную таблицу в sql-сервере?

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

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

Но я не знаю, что такое "слишком много записей". 100 000 записей? или 1000 000 записей? Как узнать, используется ли переменная таблицы в памяти или находится на диске? Есть ли какая-либо функция или инструмент в SQL Server 2005 для измерения масштаба переменной таблицы или предоставления мне знать, когда переменная таблицы помещается на диск из памяти?

Ответ 1

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

Я написал довольно обширный ответ на сайте DBA, в котором рассматриваются различия между двумя типами объектов. Это также отвечает на ваш вопрос о дисках и памяти (я не видел существенной разницы в поведении между ними).

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

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

  1. Если вам нужен индекс, который не может быть создан для табличной переменной, тогда вам, конечно, понадобится #temporary таблица. Детали этого зависят от версии, однако. Для SQL Server 2012 и ниже единственными индексами, которые могли быть созданы для табличных переменных, были те, которые неявно создавались с помощью ограничения UNIQUE или PRIMARY KEY. SQL Server 2014 представил встроенный синтаксис индекса для подмножества параметров, доступных в CREATE INDEX. С тех пор это было расширено, чтобы позволить фильтровать условия индекса. Однако по-прежнему невозможно создать индексы с столбцами INCLUDE -d или индексами columnstore для переменных таблицы.

  2. Если вы будете многократно добавлять и удалять большое количество строк в таблице, используйте таблицу #temporary. Это поддерживает TRUNCATE (который более эффективен, чем DELETE для больших таблиц), и дополнительно последующие вставки после TRUNCATE могут иметь лучшую производительность, чем те, которые следуют за DELETE как показано здесь.

  3. Если вы будете удалять или обновлять большое количество строк, тогда временная таблица может работать намного лучше, чем переменная таблицы - если она может использовать совместное использование набора строк (например, см. "Эффекты совместного использования набора строк" ниже).
  4. Если оптимальный план с использованием таблицы будет варьироваться в зависимости от данных, используйте таблицу #temporary. Это поддерживает создание статистики, которая позволяет динамически перекомпилировать план в соответствии с данными (хотя для кэшированных временных таблиц в хранимых процедурах поведение перекомпиляции необходимо понимать отдельно).
  5. Если оптимальный план для запроса с использованием таблицы вряд ли когда-либо изменится, вы можете рассмотреть возможность использования табличной переменной, чтобы пропустить издержки, связанные с созданием статистики и перекомпиляцией (возможно, потребуются подсказки, чтобы исправить план, который вы хотите).
  6. Если источником данных, вставляемых в таблицу, является потенциально дорогой SELECT то учтите, что использование табличной переменной заблокирует возможность этого при использовании параллельного плана.
  7. Если вам нужны данные в таблице, чтобы выдержать откат внешней пользовательской транзакции, используйте переменную таблицы. Возможным вариантом использования для этого может быть регистрация хода выполнения различных шагов в длинном пакете SQL.
  8. При использовании таблицы #temp в пользовательской транзакции блокировки могут удерживаться дольше, чем для табличных переменных (возможно, до конца транзакции или конца инструкции в зависимости от типа блокировки и уровня изоляции), а также это может предотвратить усечение транзакции tempdb войти, пока пользовательская транзакция не закончится. Так что это может способствовать использованию табличных переменных.
  9. В хранимых подпрограммах можно кэшировать как переменные таблицы, так и временные таблицы. Содержание метаданных для кэшированных табличных переменных меньше, чем для #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

Ответ 2

Используйте переменную таблицы , если для очень небольшого количества данных (в тысячах байтов)

Используйте временную таблицу для большого количества данных

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

В моем примере я просто хотел разместить около 20 строк в формате и изменить их как группу, прежде чем использовать их для UPDATE/INSERT для постоянной таблицы. Поэтому переменная таблицы идеальна.

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

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

Мое понимание в основном основано на http://www.developerfusion.com/article/84397/table-variables-v-temporary-tables-in-sql-server/, которое имеет гораздо более подробную информацию.

Ответ 3

Microsoft говорит здесь

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

Ответ 4

Я полностью согласен с Abacus (извините - не хватает очков для комментариев).

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

Например, рассмотрели ли вы разницу в производительности между 1000 записями с 50 столбцами по 100 000 записей, всего по 5 столбцов?

Наконец, возможно, вы запрашиваете/сохраняете больше данных, чем вам нужно? Здесь хорошо читайте стратегии оптимизации SQL. Ограничьте количество данных, которые вы вытягиваете, особенно если вы не используете все это (некоторые программисты SQL становятся ленивыми и просто выбирают все, даже если они используют только крошечное подмножество). Не забывайте, что анализатор запросов SQL также может стать вашим лучшим другом.

Ответ 5

Таблица переменных доступна только для текущего сеанса, например, если вам нужно EXEC другой хранимой процедуры в рамках текущей, вам нужно будет передать таблицу в качестве Table Valued Parameter значений и, конечно, это повлияет на производительность, с временными таблицами вы можете сделать это только с передачей временного имени таблицы

Чтобы проверить временную таблицу:

  • Редактор запросов Open Management Studio
  • Создать временную таблицу
  • Откройте другое окно редактора запросов
  • Выберите из этой таблицы "Доступно"

Чтобы проверить таблицу переменных:

  • Редактор запросов Open Management Studio
  • Создать таблицу переменных
  • Откройте другое окно редактора запросов
  • Выберите из этой таблицы "Недоступно"

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

Ответ 6

запись данных в объявленные таблицы declare @tb и после присоединения к другим таблицам я понял, что время ответа по сравнению с временными таблицами tempdb .. # tb намного выше.

Когда я присоединяюсь к ним с @tb, время намного больше, чтобы вернуть результат, в отличие от #tm, возврат почти мгновен.

Я провел тесты с 10 000 строк и присоединился к 5 другим таблицам