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

Quando dovrei usare una variabile di tabella rispetto a una tabella temporanea nel server sql?

La tua domanda mostra che hai ceduto ad alcune delle idee sbagliate comuni che circondano le variabili di tabella e le tabelle temporanee.

Ho scritto una risposta piuttosto ampia sul sito DBA esaminando le differenze tra i due tipi di oggetti. Questo risponde anche alla tua domanda su disco e memoria (non ho visto alcuna differenza significativa nel comportamento tra i due).

Per quanto riguarda la domanda nel titolo, però, su quando utilizzare una variabile di tabella rispetto a una tabella temporanea locale, non hai sempre una scelta. Nelle funzioni, ad esempio, è possibile utilizzare solo una variabile di tabella e se è necessario scrivere nella tabella in un ambito figlio, allora solo un #temp la tabella lo farà (i parametri con valori di tabella consentono l'accesso in sola lettura).

Se hai una scelta, alcuni suggerimenti sono di seguito (sebbene il metodo più affidabile sia semplicemente testare entrambi con il tuo carico di lavoro specifico).

  1. Se hai bisogno di un indice che non può essere creato su una variabile di tabella, avrai ovviamente bisogno di un #temporary tavolo. Tuttavia, i dettagli di questo dipendono dalla versione. Per SQL Server 2012 e versioni precedenti gli unici indici che potevano essere creati sulle variabili di tabella erano quelli creati implicitamente tramite un UNIQUE o PRIMARY KEY vincolo. SQL Server 2014 ha introdotto la sintassi dell'indice inline per un sottoinsieme delle opzioni disponibili in CREATE INDEX . Da allora è stato esteso per consentire condizioni di indice filtrate. Indici con INCLUDE Tuttavia, non è ancora possibile creare colonne -d o indici columnstore su variabili di tabella.

  2. Se aggiungerai ed eliminerai ripetutamente un numero elevato di righe dalla tabella, utilizza un #temporary tavolo. Questo supporta TRUNCATE (che è più efficiente di DELETE per tabelle di grandi dimensioni) e ulteriori inserimenti successivi a TRUNCATE possono avere prestazioni migliori rispetto a quelle che seguono un DELETE come illustrato qui.

  3. Se eliminerai o aggiornerai un numero elevato di righe, la tabella temporanea potrebbe funzionare molto meglio di una variabile di tabella, se è in grado di utilizzare la condivisione del set di righe (vedi "Effetti della condivisione del set di righe" di seguito per un esempio) .
  4. Se il piano ottimale che utilizza la tabella varia in base ai dati, utilizza un #temporary tavolo. Ciò supporta la creazione di statistiche che consentono la ricompilazione dinamica del piano in base ai dati (sebbene per le tabelle temporanee memorizzate nella cache nelle procedure memorizzate il comportamento di ricompilazione debba essere compreso separatamente).
  5. Se è improbabile che il piano ottimale per la query che utilizza la tabella cambi mai, puoi prendere in considerazione una variabile di tabella per saltare il sovraccarico della creazione di statistiche e ricompilazioni (potrebbe richiedere suggerimenti per correggere il piano desiderato).
  6. Se la fonte dei dati inseriti nella tabella proviene da un SELECT potenzialmente costoso istruzione quindi considera che l'utilizzo di una variabile table bloccherà la possibilità di ciò utilizzando un piano parallelo.
  7. Se hai bisogno dei dati nella tabella per sopravvivere a un rollback di una transazione utente esterna, usa una variabile di tabella. Un possibile caso d'uso potrebbe essere la registrazione dell'avanzamento di diversi passaggi in un lungo batch SQL.
  8. Quando si utilizza un #temp la tabella all'interno di una transazione utente i blocchi possono essere mantenuti più a lungo rispetto alle variabili di tabella (potenzialmente fino alla fine della transazione rispetto alla fine dell'istruzione a seconda del tipo di blocco e del livello di isolamento) e possono anche impedire il troncamento del tempdb registro delle transazioni fino al termine della transazione dell'utente. Quindi questo potrebbe favorire l'uso di variabili di tabella.
  9. All'interno delle routine memorizzate, sia le variabili di tabella che le tabelle temporanee possono essere memorizzate nella cache. La manutenzione dei metadati per le variabili di tabella memorizzate nella cache è inferiore a quella per #temporary tavoli. Bob Ward fa notare nel suo tempdb presentazione che ciò può causare ulteriore contesa sulle tabelle di sistema in condizioni di elevata concorrenza. Inoltre, quando si gestiscono piccole quantità di dati, ciò può fare una differenza misurabile in termini di prestazioni.

Effetti della condivisione del set di righe

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