Ваше запитання показує, що ви піддалися на деякі поширені помилки щодо змінних таблиць та тимчасових таблиць.
Я написав досить обширну відповідь на сайті DBA, розглядаючи відмінності між двома типами об'єктів. Це також стосується вашого питання щодо диска проти пам'яті (я не бачив суттєвої різниці в поведінці між ними).
Щодо питання в заголовку, хоча щодо того, коли використовувати змінну таблиці та локальну тимчасову таблицю, у вас не завжди є вибір. Наприклад, у функціях можна використовувати лише змінну таблиці, і якщо вам потрібно записати в таблицю в дочірньому просторі, тоді це #temp
робитиме лише таблиця (параметри, що оцінюються за таблицею, дозволяють отримати доступ лише для читання ).
Там, де у вас є вибір, наведені нижче пропозиції (хоча найнадійніший метод - просто перевірити обидва з вашим конкретним навантаженням).
Якщо вам потрібен індекс, який неможливо створити на змінній таблиці, то, звичайно, вам знадобиться #temporary
таблиця. Деталі цього залежать від версії. Для SQL Server 2012 і нижче єдиними індексами, які можна було створити на змінних таблиці, були неявні, створені через UNIQUE
або PRIMARY KEY
обмеження. SQL Server 2014 представив синтаксис вбудованого індексу для підмножини опцій, доступних у CREATE INDEX
. Це було розширено з тих пір, щоб дозволити відфільтровані умови індексу. Індекси з INCLUDE
-d стовпцями або індексами стовпців сторони все ж неможливо створити на змінних таблиці.
Якщо ви будете неодноразово додавати та видаляти велику кількість рядків із таблиці, тоді використовуйте #temporary
таблицю. Ця підтримка TRUNCATE
(яка є більш ефективною, ніж DELETE
для великих таблиць) та додатково наступні вставки, наступні за a, TRUNCATE
можуть мати кращі показники, ніж ті, що слідують за, 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
- те, що "в пам'яті" є міфом. Також: змінні таблиці завжди будуть враховані оптимізатором запитів, щоб утримувати рівно один рядок - якщо у вас набагато більше, це може призвести до серйозно поганих планів виконання.