Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Кога трябва да използвам променлива на таблица срещу временна таблица в sql сървър?

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

Написах доста обширен отговор на сайта на DBA, разглеждайки разликите между двата типа обекти. Това също се отнася до въпроса ви относно диска спрямо паметта (не видях съществена разлика в поведението между двете).

По отношение на въпроса в заглавието обаче кога да използвате променлива на таблица срещу локална временна таблица, вие не винаги имате избор. Във функциите, например, е възможно да се използва само променлива на таблица и ако трябва да пишете в таблицата в дъщерен обхват, тогава само #temp table ще направи (параметрите с стойност на таблица позволяват достъп само за четене).

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

  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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL заявка 'LIKE', използваща '%', където критериите за търсене съдържат '%'

  2. Разделяне на стойности, разделени със запетая, в колони на множество редове в Sql Server

  3. PARSE() срещу TRY_PARSE() в SQL Server:Каква е разликата?

  4. База данни + удостоверяване на Windows + потребителско име/парола?

  5. Използвайте SET TEXTSIZE, за да ограничите връщаните данни за всеки ред в SQL Server