sql >> Database >  >> RDS >> Sqlserver

Wanneer moet ik een tabelvariabele gebruiken versus een tijdelijke tabel op de sql-server?

Uw vraag laat zien dat u bent bezweken voor enkele van de veelvoorkomende misvattingen over tabelvariabelen en tijdelijke tabellen.

Ik heb een vrij uitgebreid antwoord geschreven op de DBA-site en kijk naar de verschillen tussen de twee objecttypen. Dit beantwoordt ook uw vraag over schijf versus geheugen (ik zag geen significant verschil in gedrag tussen de twee).

Wat betreft de vraag in de titel over wanneer je een tabelvariabele versus een lokale tijdelijke tabel moet gebruiken, heb je niet altijd een keuze. In functies is het bijvoorbeeld alleen mogelijk om een ​​tabelvariabele te gebruiken en als u naar de tabel in een onderliggende scope moet schrijven, dan alleen een #temp tabel zal doen (parameter met tabelwaarde staat alleen-lezen toegang toe).

Waar u wel een keuze heeft, vindt u hieronder enkele suggesties (hoewel de meest betrouwbare methode is om beide te testen met uw specifieke werklast).

  1. Als je een index nodig hebt die niet kan worden gemaakt op een tabelvariabele, dan heb je natuurlijk een #temporary nodig tafel. De details hiervan zijn echter versie-afhankelijk. Voor SQL Server 2012 en lager waren de enige indexen die op tabelvariabelen konden worden gemaakt, de indexen die impliciet waren gemaakt via een UNIEKE of PRIMAIRE SLEUTEL beperking. SQL Server 2014 introduceerde inline indexsyntaxis voor een subset van de opties die beschikbaar zijn in CREATE INDEX . Dit is sindsdien uitgebreid om gefilterde indexvoorwaarden mogelijk te maken. Indexen met INCLUDE -d kolommen of columnstore-indexen kunnen echter nog steeds niet worden gemaakt op tabelvariabelen.

  2. Als u herhaaldelijk grote aantallen rijen aan de tabel toevoegt en verwijdert, gebruik dan een #tijdelijk tafel. Dat ondersteunt TRUNCATE (wat efficiënter is dan DELETE voor grote tabellen) en aanvullende invoegingen na een TRUNCATE kunnen betere prestaties leveren dan die na een DELETE zoals hier geïllustreerd.

  3. Als u een groot aantal rijen gaat verwijderen of bijwerken, presteert de tijdelijke tabel mogelijk veel beter dan een tabelvariabele - als deze het delen van rijensets kan gebruiken (zie "Effecten van het delen van rijen" hieronder voor een voorbeeld) .
  4. Als het optimale plan voor het gebruik van de tabel afhankelijk is van de gegevens, gebruik dan een #tijdelijk tafel. Dat ondersteunt het maken van statistieken waarmee het plan dynamisch opnieuw kan worden gecompileerd op basis van de gegevens (hoewel voor tijdelijke tabellen in de cache in opgeslagen procedures het hercompilatiegedrag afzonderlijk moet worden begrepen).
  5. Als het onwaarschijnlijk is dat het optimale plan voor de query met behulp van de tabel ooit zal veranderen, kunt u een tabelvariabele overwegen om de overhead van het maken van statistieken en het opnieuw compileren over te slaan (u hebt mogelijk hints nodig om het gewenste plan te repareren).
  6. Als de bron voor de gegevens die in de tabel zijn ingevoegd afkomstig is van een mogelijk dure SELECT verklaring, bedenk dan dat het gebruik van een tabelvariabele de mogelijkheid hiervan met een parallel plan zal blokkeren.
  7. Als je de gegevens in de tabel nodig hebt om een ​​terugdraaiing van een externe gebruikerstransactie te overleven, gebruik dan een tabelvariabele. Een mogelijke use case hiervoor is het loggen van de voortgang van verschillende stappen in een lange SQL-batch.
  8. Bij gebruik van een #temp tabel binnen een gebruiker transactievergrendelingen kunnen langer worden vastgehouden dan voor tabelvariabelen (mogelijk tot het einde van de transactie versus het einde van de verklaring, afhankelijk van het type vergrendeling en isolatieniveau) en het kan ook voorkomen dat de tempdb transactielogboek totdat de gebruikerstransactie eindigt. Dit zou dus het gebruik van tabelvariabelen kunnen bevorderen.
  9. Binnen opgeslagen routines kunnen zowel tabelvariabelen als tijdelijke tabellen in de cache worden opgeslagen. Het onderhoud van metagegevens voor tabelvariabelen in de cache is minder dan voor #tijdelijk tafels. Bob Ward wijst erop in zijn tempdb presentatie dat dit bij hoge gelijktijdigheid kan leiden tot extra twist op systeemtabellen. Bovendien kan dit bij het omgaan met kleine hoeveelheden gegevens een meetbaar verschil maken voor de prestaties.

Effecten van het delen van rijen

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. SQL Server Error 7222:"Alleen een SQL Server-provider is toegestaan ​​op dit exemplaar"

  2. Hoe te controleren welke sloten op een tafel worden vastgehouden?

  3. Postgres ontbreekt FROM-clausule invoerfout bij query met WITH-component

  4. Tijdzoneopslag in tijdstempel van gegevenstype met tijdzone