sql >> Databáze >  >> RDS >> Sqlserver

Kdy bych měl použít proměnnou tabulky vs dočasnou tabulku na serveru SQL?

Vaše otázka ukazuje, že jste podlehli některým běžným mylným představám o proměnných tabulek a dočasných tabulkách.

Napsal jsem poměrně rozsáhlou odpověď na stránce DBA, kde jsem se podíval na rozdíly mezi těmito dvěma typy objektů. To také řeší vaši otázku ohledně disku vs paměti (neviděl jsem žádný významný rozdíl v chování mezi těmito dvěma).

Pokud jde o otázku v názvu, kdy použít proměnnou tabulky vs místní dočasnou tabulku, nemáte vždy na výběr. Ve funkcích je například možné použít pouze proměnnou tabulky a pokud potřebujete zapisovat do tabulky v podřízeném rozsahu, pak pouze #temp tabulka udělá (parametry s hodnotou tabulky umožňují přístup pouze pro čtení).

Pokud máte na výběr, některé návrhy jsou uvedeny níže (ačkoli nejspolehlivější metodou je jednoduše otestovat obojí s vaší konkrétní pracovní zátěží).

  1. Pokud potřebujete index, který nelze vytvořit na proměnné tabulky, budete samozřejmě potřebovat #temporary stůl. Podrobnosti jsou však závislé na verzi. Pro SQL Server 2012 a nižší byly jediné indexy, které bylo možné vytvořit pro proměnné tabulky, ty implicitně vytvořené prostřednictvím UNIQUE nebo PRIMARY KEY omezení. SQL Server 2014 zavedl inline syntaxi indexu pro podmnožinu možností dostupných v CREATE INDEX . To bylo od té doby rozšířeno, aby umožnilo podmínky filtrovaného indexu. Indexuje pomocí INCLUDE -d sloupce nebo indexy sloupců však stále není možné vytvořit na proměnných tabulky.

  2. Pokud budete opakovaně přidávat a odstraňovat velké množství řádků z tabulky, použijte #temporary stůl. To podporuje TRUNCATE (což je efektivnější než DELETE pro velké tabulky) a další následné vložení za TRUNCATE mohou mít lepší výkon než ty, které následují po DELETE jak je znázorněno zde.

  3. Pokud budete mazat nebo aktualizovat velký počet řádků, může dočasná tabulka fungovat mnohem lépe než proměnná tabulky – pokud je schopna používat sdílení sady řádků (příklad viz „Efekty sdílení sady řádků“ níže) .
  4. Pokud se optimální plán pomocí tabulky bude lišit v závislosti na datech, použijte #temporary stůl. To podporuje vytváření statistik, které umožňují dynamickou rekompilaci plánu podle dat (ačkoli u dočasných tabulek uložených v mezipaměti v uložených procedurách je třeba chování při rekompilaci chápat samostatně).
  5. Pokud je nepravděpodobné, že by se optimální plán pro dotaz využívající tabulku někdy změnil, můžete zvážit proměnnou tabulky, abyste přeskočili režii vytváření statistik a překompilování (možná bude vyžadovat nápovědu k opravě požadovaného plánu).
  6. Pokud zdroj dat vložených do tabulky pochází z potenciálně drahého SELECT potom zvažte, že použití proměnné tabulky zablokuje možnost tohoto použití paralelního plánu.
  7. Pokud potřebujete, aby data v tabulce přežila vrácení transakce vnějšího uživatele, použijte proměnnou tabulky. Možným případem použití může být protokolování průběhu různých kroků v dlouhé dávce SQL.
  8. Při použití #temp tabulka uvnitř uživatelského transakčního zámku může být držena déle než u proměnných tabulky (potenciálně až do konce transakce vs. konec příkazu v závislosti na typu zámku a úrovni izolace) a také může zabránit zkrácení tempdb transakční protokol, dokud uživatelská transakce neskončí. To by tedy mohlo upřednostňovat použití proměnných tabulky.
  9. V rámci uložených rutin lze do mezipaměti ukládat jak proměnné tabulky, tak dočasné tabulky. Údržba metadat pro proměnné tabulky uložené v mezipaměti je menší než pro #temporary tabulky. Bob Ward poukazuje ve své tempdb prezentace, že to může způsobit další spory o systémových tabulkách za podmínek vysoké souběžnosti. Navíc při práci s malým množstvím dat to může mít měřitelný rozdíl ve výkonu.

Efekty sdílení sady řádků

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. Jak přejmenovat něco na serveru SQL Server, který má v názvu hranaté závorky?

  2. Nastavení Django na používání MySQL

  3. SQL Server 2008 – Jak vrátím uživatelsky definovaný typ tabulky z funkce s hodnotou tabulky?

  4. Funkce SYSTIMESTAMP v Oracle