sql >> Database teknologi >  >> RDS >> Sqlserver

Hvornår skal jeg bruge en tabelvariabel vs midlertidig tabel i sql-serveren?

Dit spørgsmål viser, at du er bukket under for nogle af de almindelige misforståelser omkring tabelvariabler og midlertidige tabeller.

Jeg har skrevet et ret omfattende svar på DBA's side, hvor jeg ser på forskellene mellem de to objekttyper. Dette adresserer også dit spørgsmål om disk vs hukommelse (jeg så ikke nogen væsentlig forskel i adfærd mellem de to).

Med hensyn til spørgsmålet i titlen om hvornår man skal bruge en tabelvariabel kontra en lokal midlertidig tabel, har man dog ikke altid et valg. I funktioner er det for eksempel kun muligt at bruge en tabelvariabel, og hvis du skal skrive til tabellen i et child scope, så er det kun en #temp tabel vil gøre (tabel-værdi parametre tillader skrivebeskyttet adgang).

Hvor du har et valg, er nogle forslag nedenfor (selvom den mest pålidelige metode er blot at teste begge med din specifikke arbejdsbyrde).

  1. Hvis du har brug for et indeks, der ikke kan oprettes på en tabelvariabel, skal du naturligvis bruge en #temporary bord. Detaljerne i dette er dog versionsafhængige. For SQL Server 2012 og derunder var de eneste indekser, der kunne oprettes på tabelvariabler dem, der var implicit oprettet gennem en UNIQUE eller PRIMARY KEY begrænsning. SQL Server 2014 introducerede indbygget indekssyntaks for en undergruppe af de tilgængelige muligheder i CREATE INDEX . Dette er blevet forlænget siden for at tillade filtrerede indeksforhold. Indekser med INCLUDE -d-kolonner eller columnstore-indekser er dog stadig ikke mulige at oprette på tabelvariabler.

  2. Hvis du gentagne gange vil tilføje og slette et stort antal rækker fra tabellen, skal du bruge en #temporary bord. Det understøtter TRUNCATE (hvilket er mere effektivt end DELETE for store tabeller) og yderligere efterfølgende indsættelser efter en TRUNCATE kan have bedre ydeevne end dem efter en DELETE som illustreret her.

  3. Hvis du vil slette eller opdatere et stort antal rækker, kan den midlertidige tabel muligvis fungere meget bedre end en tabelvariabel - hvis den er i stand til at bruge rækkesætdeling (se "Effekter af rækkesætdeling" nedenfor for et eksempel) .
  4. Hvis den optimale plan ved hjælp af tabellen vil variere afhængigt af data, så brug en #temporary bord. Det understøtter oprettelse af statistikker, som gør det muligt for planen at blive dynamisk rekompileret i overensstemmelse med dataene (selvom for cachelagrede midlertidige tabeller i lagrede procedurer skal rekompileringsadfærden forstås separat).
  5. Hvis det er usandsynligt, at den optimale plan for forespørgslen ved hjælp af tabellen nogensinde ændrer sig, kan du overveje en tabelvariabel for at springe over overheaden ved oprettelse af statistik og genkompilering (vil muligvis kræve tip til at rette den plan, du ønsker).
  6. Hvis kilden til de data, der er indsat i tabellen, er fra en potentielt dyr SELECT sætning, så overvej, at brug af en tabelvariabel vil blokere muligheden for dette ved at bruge en parallel plan.
  7. Hvis du har brug for dataene i tabellen for at overleve en tilbagerulning af en ydre brugertransaktion, så brug en tabelvariabel. En mulig use case for dette kan være at logge forløbet af forskellige trin i en lang SQL-batch.
  8. Når du bruger en #temp tabel i en bruger transaktionslåse kan holdes længere end for tabelvariabler (potentielt indtil slutningen af ​​transaktionen vs slutningen af ​​sætningen afhængig af typen af ​​lås og isolationsniveau), og det kan også forhindre trunkering af tempdb transaktionslog indtil brugertransaktionen slutter. Så dette kan begunstige brugen af ​​tabelvariabler.
  9. Inden for lagrede rutiner kan både tabelvariabler og midlertidige tabeller cachelagres. Metadatavedligeholdelsen for cachelagrede tabelvariabler er mindre end for #temporary tabeller. Bob Ward påpeger i sin tempdb præsentation af, at dette kan forårsage yderligere uenighed på systemtabeller under forhold med høj samtidighed. Når der er tale om små mængder data, kan dette desuden gøre en målbar forskel for ydeevnen.

Effekter af rækkesætdeling

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. Sammenligning af fejltider for Amazon Aurora, Amazon RDS og ClusterControl

  2. Sikkerhedskopier en SQLite-database

  3. Identitetskolonnens værdi springer pludselig til 1001 i sql-serveren

  4. JPA Tabelnavne med store bogstaver