Quali sono più performanti CTE
o Temporary Tables
?
Quali sono più performanti CTE
o Temporary Tables
?
Risposte:
Direi che sono concetti diversi ma non troppo diversi per dire "gesso e formaggio".
Una tabella temporanea è utile per il riutilizzo o per eseguire più passaggi di elaborazione su un set di dati.
Un CTE può essere usato per fare ricorso o per migliorare semplicemente la leggibilità.
Inoltre, come una vista o una tabella di funzioni incorporate, la funzione valutata può anche essere trattata come una macro da espandere nella query principale
Una tabella temporanea è un'altra tabella con alcune regole relative all'ambito
Ho memorizzato proc dove uso entrambi (e anche le variabili di tabella)
cte vs temporary tables
quindi IMHO questa risposta deve evidenziare meglio gli svantaggi di CTE. TL; DR della risposta collegata: un CTE non dovrebbe mai essere usato per le prestazioni. . Sono d'accordo con quella citazione poiché ho sperimentato gli aspetti negativi di CTE.
Dipende.
Prima di tutto
Che cos'è un'espressione di tabella comune?
Un CTE (non ricorsivo) viene trattato in modo molto simile ad altri costrutti che possono anche essere utilizzati come espressioni di tabella incorporate in SQL Server. Tabelle derivate, viste e funzioni con valori di tabella incorporate. Si noti che mentre BOL afferma che un CTE "può essere pensato come un set di risultati temporaneo", questa è una descrizione puramente logica. Il più delle volte non è materializzato a sé stante.
Che cos'è una tabella temporanea?
Questa è una raccolta di righe memorizzate su pagine di dati in tempdb. Le pagine dei dati possono risiedere in parte o interamente in memoria. Inoltre, la tabella temporanea può essere indicizzata e avere statistiche di colonna.
Dati di test
CREATE TABLE T(A INT IDENTITY PRIMARY KEY, B INT , F CHAR(8000) NULL);
INSERT INTO T(B)
SELECT TOP (1000000) 0 + CAST(NEWID() AS BINARY(4))
FROM master..spt_values v1,
master..spt_values v2;
Esempio 1
WITH CTE1 AS
(
SELECT A,
ABS(B) AS Abs_B,
F
FROM T
)
SELECT *
FROM CTE1
WHERE A = 780
Si noti che nel piano sopra non è menzionato CTE1. Accede direttamente alle tabelle di base e viene trattato come
SELECT A,
ABS(B) AS Abs_B,
F
FROM T
WHERE A = 780
Riscrivere materializzando il CTE in una tabella temporanea intermedia qui sarebbe fortemente controproducente.
Materializzare la definizione CTE di
SELECT A,
ABS(B) AS Abs_B,
F
FROM T
Implicherebbe la copia di circa 8 GB di dati in una tabella temporanea, quindi c'è ancora il sovraccarico di selezionare da esso.
Esempio 2
WITH CTE2
AS (SELECT *,
ROW_NUMBER() OVER (ORDER BY A) AS RN
FROM T
WHERE B % 100000 = 0)
SELECT *
FROM CTE2 T1
CROSS APPLY (SELECT TOP (1) *
FROM CTE2 T2
WHERE T2.A > T1.A
ORDER BY T2.A) CA
L'esempio sopra richiede circa 4 minuti sulla mia macchina.
Solo 15 righe dei 1.000.000 di valori generati casualmente corrispondono al predicato, ma la costosa scansione della tabella avviene 16 volte per localizzarli.
Questo sarebbe un buon candidato per materializzare il risultato intermedio. La riscrittura della tabella temporanea equivalente ha richiesto 25 secondi.
INSERT INTO #T
SELECT *,
ROW_NUMBER() OVER (ORDER BY A) AS RN
FROM T
WHERE B % 100000 = 0
SELECT *
FROM #T T1
CROSS APPLY (SELECT TOP (1) *
FROM #T T2
WHERE T2.A > T1.A
ORDER BY T2.A) CA
La materializzazione intermedia di una parte di una query in una tabella temporanea può talvolta essere utile anche se viene valutata una sola volta, quando consente di ricompilare il resto della query sfruttando le statistiche sul risultato materializzato. Un esempio di questo approccio è nell'articolo di SQL Cat su quando scomporre query complesse .
In alcune circostanze, SQL Server utilizzerà uno spool per memorizzare nella cache un risultato intermedio, ad esempio un CTE, evitando di dover rivalutare quel sottoalbero. Questo è discusso nell'elemento Connect (migrato) Fornire un suggerimento per forzare la materializzazione intermedia di CTE o tabelle derivate . Tuttavia, non vengono create statistiche su questo e anche se il numero di righe di spooling dovesse essere enormemente diverso da quello stimato, non è possibile per il piano di esecuzione in corso di adattarsi dinamicamente in risposta (almeno nelle versioni attuali. Piani di query adattive possono diventare possibili in il futuro).
Il CTE ha i suoi usi - quando i dati nel CTE sono piccoli e c'è un forte miglioramento della leggibilità come nel caso delle tabelle ricorsive. Tuttavia, le sue prestazioni non sono certamente migliori delle variabili di tabella e quando si ha a che fare con tabelle molto grandi, le tabelle temporanee superano significativamente le CTE. Questo perché non è possibile definire indici su un CTE e quando si dispone di una grande quantità di dati che richiedono l'unione con un'altra tabella (CTE è semplicemente come una macro). Se si uniscono più tabelle con milioni di righe di record in ciascuna, CTE avrà prestazioni significativamente peggiori rispetto alle tabelle temporanee.
Le tabelle temporanee sono sempre su disco - quindi finché il tuo CTE può essere tenuto in memoria, molto probabilmente sarebbe più veloce (come anche una variabile di tabella).
Ma ancora una volta, se il carico di dati del tuo CTE (o variabile della tabella temporanea) diventa troppo grande, verrà archiviato anche sul disco, quindi non ci sono grandi vantaggi.
In generale, preferisco un CTE rispetto a una tabella temporanea poiché è andato dopo che l'ho usato. Non ho bisogno di pensare a lasciarlo cadere esplicitamente o altro.
Quindi, nessuna risposta chiara alla fine, ma personalmente, preferirei CTE rispetto alle tabelle temporanee.
Quindi la query che mi è stata assegnata per l'ottimizzazione è stata scritta con due CTE nel server SQL. Ci vollero 28 secondi.
Ho impiegato due minuti a convertirli in tabelle temporanee e la query ha richiesto 3 secondi
Ho aggiunto un indice alla tabella temporanea sul campo su cui era stato unito e l'ho ridotto a 2 secondi
Tre minuti di lavoro e ora funziona 12 volte più velocemente rimuovendo CTE. Personalmente non userò CTE mai sono anche più difficili da eseguire il debug.
La cosa folle è che i CTE sono stati entrambi usati solo una volta e che ancora inserendo un indice su di essi si è rivelato più veloce del 50%.
CTE non occuperà spazio fisico. È solo un set di risultati che possiamo usare join.
Le tabelle temporanee sono temporanee. Possiamo creare indici, vincoli come normali tabelle per cui dobbiamo definire tutte le variabili.
Ambito della tabella temporanea solo all'interno della sessione. ES: aprire due finestre di query SQL
create table #temp(empid int,empname varchar)
insert into #temp
select 101,'xxx'
select * from #temp
Esegui questa query nella prima finestra, quindi esegui la query seguente nella seconda finestra, puoi trovare la differenza.
select * from #temp
Ho usato entrambi, ma in enormi procedure complesse ho sempre trovato le tabelle temporanee migliori con cui lavorare e più metodiche. I CTE hanno i loro usi ma generalmente con piccoli dati.
Ad esempio, ho creato sprocs che restituiscono i risultati di calcoli di grandi dimensioni in 15 secondi, convertendo tuttavia questo codice per l'esecuzione in un CTE e l'ho visto funzionare per più di 8 minuti per ottenere gli stessi risultati.
In ritardo alla festa, ma ...
L'ambiente in cui lavoro è fortemente limitato, supporta alcuni prodotti del fornitore e fornisce servizi "a valore aggiunto" come i report. A causa delle limitazioni della politica e del contratto, di solito non mi è concesso il lusso di spazio separato tabella / dati e / o la possibilità di creare codice permanente [migliora un po ', a seconda dell'applicazione].
IOW, non posso solito sviluppare una procedura memorizzata o UDF o tabelle temporanee, ecc. Devo praticamente fare tutto tramite la MIA interfaccia dell'applicazione (Crystal Reports: aggiungere / collegare tabelle, impostare dove clausole da w / in CR, ecc. ). Una piccola grazia salvifica è che Crystal mi consente di utilizzare i COMANDI (così come le espressioni SQL). Alcune cose che non sono efficienti attraverso la normale funzionalità di aggiunta / collegamento delle tabelle possono essere fatte definendo un comando SQL. Uso i CTE e ho ottenuto ottimi risultati "da remoto". I CTE aiutano anche a segnalare la manutenzione, senza richiedere che il codice venga sviluppato, consegnato a un DBA per compilare, crittografare, trasferire, installare e quindi richiedere test a più livelli. Posso fare CTE tramite l'interfaccia locale.
Il lato negativo dell'utilizzo di CTE con CR è che ogni rapporto è separato. Ogni CTE deve essere mantenuto per ogni rapporto. Dove posso fare SP e UDF, posso sviluppare qualcosa che può essere utilizzato da più report, richiedendo solo il collegamento a SP e passando parametri come se stessi lavorando su una tabella normale. CR non è davvero bravo a gestire i parametri nei comandi SQL, quindi può mancare l'aspetto dell'aspetto CR / CTE. In questi casi, di solito provo a definire il CTE per restituire dati sufficienti (ma non TUTTI i dati), e quindi utilizzare le funzionalità di selezione dei record in CR per dividere e tagliare.
Quindi ... il mio voto è per CTE (fino a quando non avrò il mio spazio dati).
Un uso in cui ho trovato le prestazioni eccellenti di CTE era dove dovevo unire una query relativamente complessa su alcuni tavoli che avevano alcuni milioni di righe ciascuno.
Ho usato il CTE per selezionare prima il sottoinsieme in base alle colonne indicizzate per tagliare prima queste tabelle in alcune migliaia di righe pertinenti ciascuna e poi ho unito il CTE alla mia query principale. Ciò ha ridotto esponenzialmente il tempo di esecuzione della mia query.
Mentre i risultati per il CTE non sono memorizzati nella cache e le variabili di tabella avrebbero potuto essere una scelta migliore, volevo davvero provarli e ho trovato lo scenario sopra indicato.
Questa è una domanda davvero aperta, e tutto dipende da come viene utilizzato e dal tipo di tabella temporanea (tabella variabile o tabella tradizionale).
Una tabella temporanea tradizionale memorizza i dati nel DB temporaneo, che rallenta le tabelle temporanee; tuttavia le variabili della tabella no.
Ho appena provato questo: sia CTE che non-CTE (dove la query è stata digitata per ogni istanza sindacale) hanno richiesto entrambi ~ 31 secondi. CTE ha reso il codice molto più leggibile, ma lo ha ridotto da 241 a 130 righe, il che è molto bello. La tabella temporanea invece l'ha ridotta a 132 righe e ha impiegato CINQUE SECONDI per l'esecuzione. Nessun scherzo. tutti questi test sono stati memorizzati nella cache: le query erano state eseguite più volte in precedenza.
Dalla mia esperienza in SQL Server, ho trovato uno degli scenari in cui CTE ha superato la tabella Temp
Avevo bisogno di usare un DataSet (~ 100000) da una query complessa UNA VOLTA nella mia procedura memorizzata.
La tabella temporanea stava causando un sovraccarico su SQL in cui la mia procedura stava funzionando lentamente (poiché le tabelle temporanee sono tabelle materializzate reali che esistono in tempdb e persistono per la durata della mia procedura corrente)
D'altra parte, con CTE, CTE persiste solo fino a quando non viene eseguita la seguente query. Quindi, CTE è una pratica struttura in memoria con Scope limitato. I CTE non usano tempdb per impostazione predefinita.
Questo è uno scenario in cui i CTE possono davvero aiutare a semplificare il codice e la tabella delle temp. Avevo usato 2 CTE, qualcosa del genere
WITH CTE1(ID, Name, Display)
AS (SELECT ID,Name,Display from Table1 where <Some Condition>),
CTE2(ID,Name,<col3>) AS (SELECT ID, Name,<> FROM CTE1 INNER JOIN Table2 <Some Condition>)
SELECT CTE2.ID,CTE2.<col3>
FROM CTE2
GO