Коли я повинен використовувати змінну таблиці та тимчасову таблицю на сервері sql?


298

Я дізнаюся більше деталей у змінній таблиці. У ньому йдеться про те, що тимчасові таблиці завжди на диску, а змінні таблиці - у пам'яті, тобто продуктивність змінної таблиці краща, ніж таблиця temp, оскільки таблична змінна використовує менше операцій вводу-виводу, ніж таблиця temp.

Але іноді, якщо в змінній таблиці є занадто багато записів, які не можуть міститися в пам'яті, змінна таблиці буде розміщена на диску, як таблиця temp.

Але я не знаю, що таке "занадто багато записів". 100 000 записів? чи 1000 000 записів? Як я можу дізнатися, чи використовувана я змінною таблиці є в пам'яті чи на диску? Чи є якась функція чи інструмент у SQL Server 2005 для вимірювання масштабу змінної таблиці або для того, щоб повідомити мені, коли табличну змінну кладуть на диск із пам'яті?


5
Змінна таблиця майже завжди є tempDB- те, що "в пам'яті" є міфом. Також: змінні таблиці завжди будуть враховані оптимізатором запитів, щоб утримувати рівно один рядок - якщо у вас набагато більше, це може призвести до серйозно поганих планів виконання.
marc_s

Це може бути вам корисним stackoverflow.com/questions/27894/…
Ігор Борисенко

2
@marc_s - Ви можете залишити "майже" у цьому виписці. Він завжди знаходиться tempdb(але може також повністю запам'ятатись)
Мартін Сміт

2
За допомогою SQL 2014 тепер ви можете створити змінну таблиці в пам'яті
папараццо

Відповіді:


362

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

Я написав досить обширну відповідь на сайті DBA, розглядаючи відмінності між двома типами об'єктів. Це також стосується вашого питання щодо диска проти пам'яті (я не бачив суттєвої різниці в поведінці між ними).

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

Там, де у вас є вибір, наведені нижче пропозиції (хоча найнадійніший метод - просто перевірити обидва з вашим конкретним навантаженням).

  1. Якщо вам потрібен індекс, який неможливо створити на змінній таблиці, то, звичайно, вам знадобиться #temporaryтаблиця. Деталі цього залежать від версії. Для SQL Server 2012 і нижче єдиними індексами, які можна було створити на змінних таблиці, були неявні, створені через UNIQUEабо PRIMARY KEYобмеження. SQL Server 2014 представив синтаксис вбудованого індексу для підмножини опцій, доступних у CREATE INDEX. Це було розширено з тих пір, щоб дозволити відфільтровані умови індексу. Індекси з INCLUDE-d стовпцями або індексами стовпців сторони все ж неможливо створити на змінних таблиці.

  2. Якщо ви будете неодноразово додавати та видаляти велику кількість рядків із таблиці, тоді використовуйте #temporaryтаблицю. Ця підтримка TRUNCATE(яка є більш ефективною, ніж DELETEдля великих таблиць) та додатково наступні вставки, наступні за a, 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
Привіт, містере Мартін Сміт. У такому випадку я просто хочу зберегти набір значень Ids, щоб використовувати їх у інших запитах всередині процедури Store. То що ти мені рекомендуєш?
Жанкарло Фонталво

@JeancarloFontalvo - таблична змінна з первинним ключем idта використанням OPTION (RECOMPILE), ймовірно, для цього буде чудово - але протестуйте обидва.
Мартін Сміт

чи є суперечність метаданих однаковою як для тимчасової таблиці, так і для змінної таблиці?
Syed Aqeel Ashiq

@Syed. Взагалі менше для телебачення. Блокування може бути звільнено раніше, якщо всередині операції користувача. Також дивіться посилання Bob Ward.
Мартін Сміт

73

Використовуйте змінну таблиці, якщо для дуже малої кількості даних (тис. Байт)

Використовуйте тимчасову таблицю для великої кількості даних

Ще один спосіб подумати над цим: якщо ви думаєте, що ви можете отримати користь від індексу, автоматизованої статистики або будь-якої користі для оптимізатора SQL, то ваш набір даних, мабуть, занадто великий для змінної таблиці.

У своєму прикладі я просто хотів поставити близько 20 рядків у формат і змінити їх як групу, перш ніж використовувати їх для ОБНОВЛЕННЯ / ВСТАВКИ постійної таблиці. Тож змінна таблиця ідеальна.

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

Це не на відміну від того, як CTE викликає занепокоєння з подібних причин розміру - якщо даних у CTE дуже мало, я вважаю, що CTE працює так само добре, як краще, ніж оптимізатор, але якщо він досить великий, то це шкодить вам погано.

Моє розуміння здебільшого базується на http://www.developerfusion.com/article/84397/table-variables-v-temporary-tables-in-sql-server/ , який має набагато більше деталей.


Змінна таблиця виносних таблиць добре підходить для невеликих наборів даних, але використовувати таблицю темп для більшого набору даних. У мене запит із тисячами рядків. Перемикаючись із змінної таблиці на таблицю temp, час запиту зменшується з 40-х до всього 5с, при цьому всі інші рівні.
лян

42

Microsoft каже тут

Змінні таблиці не мають статистики розподілу, вони не запускають перекомпіляції. Тому в багатьох випадках оптимізатор будує план запитів на основі припущення, що змінна таблиці не має рядків. З цієї причини вам слід бути обережними щодо використання змінної таблиці, якщо ви очікуєте, що більша кількість рядків (більше 100). Тимчасові таблиці можуть бути кращим рішенням у цьому випадку.


14

Я повністю згоден з Абаком (вибачте - не вистачає балів для коментарів).

Також майте на увазі, що це не обов'язково зводиться до кількості записів у вас, а до розміру ваших записів.

Наприклад, чи розглядали ви різницю між 1000 записів із 50 стовпцями проти 100000 записів із лише 5 стовпцями?

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


4

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

Щоб перевірити тимчасову таблицю:

  • Відкритий редактор запитів студії управління
  • Створіть тимчасову таблицю
  • Відкрийте ще одне вікно редактора запитів
  • Виберіть із цієї таблиці "Доступно"

Щоб перевірити таблицю змінної:

  • Відкритий редактор запитів студії управління
  • Створіть таблицю змінних
  • Відкрийте ще одне вікно редактора запитів
  • Виберіть із цієї таблиці "Недоступно"

щось інше, що я пережив, це: Якщо у вашої схеми немає GRANTпривілею створювати таблиці, тоді використовуйте змінні таблиці.


3

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

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

Я робив тести з об'єднанням 10 000 рядків і з'єднувався з 5 іншими таблицями


Чи можете ви опублікувати тест, який ви пройшли, щоб отримати ці цифри?
Dan Def
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.