Quali sono le tabelle più performanti, CTE o temporanee?


Risposte:


62

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)


12
Le tabelle temporanee consentono anche gli indici e persino le statistiche che a volte sono necessari, mentre un CTE no.
CodeCowboyOrg

9
Penso che questa risposta non evidenzi abbastanza il fatto che i CTE possono portare a prestazioni terribili. Di solito mi riferisco a questa risposta su dba.stackexchange. La mia domanda arriva al secondo posto nel mio motore di ricerca se sto osservando, cte vs temporary tablesquindi 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.
TT.

2
@TT. Interessante. Trovo che i CTE
abbiano

198

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

Piano 1

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.

inserisci qui la descrizione dell'immagine

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 

Con piano

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).


33
Questa è l'unica risposta che risponde alla domanda reale (che sta chiedendo quale ha prestazioni migliori non qual è la differenza o quale è la tua preferita) e risponde correttamente a questa domanda: "Dipende" è la risposta giusta. È anche l'unica risposta con dati di supporto da spiegare, molti altri (con un alto numero di voti) fanno affermazioni definitive che uno è migliore dell'altro senza riferimenti o prove ... Per essere chiari, tutte quelle risposte sono anche sbagliate . Perché "Dipende"
Arkaine55,

2
È anche una risposta ben scritta e ben citata. Davvero il massimo.
Dan Williams,

50

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.


9
L'ho visto per esperienza personale. I CTE si comportano in modo significativamente più lento.
goku_da_master,

7
I CTE funzionano anche più lentamente perché i risultati non vengono memorizzati nella cache. Quindi ogni volta che usi il CTE esegue nuovamente la query, il piano e tutto il resto.
goku_da_master,

1
E il motore db può scegliere di rieseguire la query non solo per ogni riferimento, ma per ogni riga della query del consumatore, come una sottoquery correlata ... è necessario fare attenzione a ciò se non lo si desidera.
Mike M,

La tabella temporanea è archiviata in tempdb su SQL Server, che è disco ma ha il vantaggio di essere indicizzato e l'ottimizzatore SQL funziona bene su query selezionate in quel caso. Non sono sicuro su quale db o area del disco sia memorizzato il CTE (quando supera la dimensione della memoria ed è in coda per il paging IO) ma non viene mai ottimizzato con il grande volume di dati. Ho usato l'opzione del compilatore (con ricompilazione) a volte per renderlo più veloce
rmehra76

33

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.


2
Nel caso di SQLite e PostgreSQL, le tabelle temporanee vengono automaticamente eliminate (di solito alla fine di una sessione). Non conosco altri DBMS però.
Serrano,

1
CTE è come una vista temporanea. I dati AFAIK non vengono archiviati, quindi nulla può essere conservato in memoria o archiviato su disco. Nota importante, ogni volta che si utilizza CTE la query viene eseguita nuovamente.
Rob,

1
Personalmente non ho mai visto un CTE funzionare meglio di una tabella Temp per la velocità. E il debug è molto più semplice con la tabella temporanea
Mark Monforti,

7

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%.


6

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

4
>> "è solo un set di risultati che possiamo usare join." -> Questo non è accurato. CTE non è un "set di risultati" ma un codice incorporato. Il motore di query di SQL Server analizza il codice CTE come parte del testo della query e crea un piano di esecuzione secondo. L'idea che CTE sia in linea è il grande vantaggio dell'utilizzo di CTE, poiché consente al server di creare un "piano di esecuzione combinato"
Ronen Ariely,

4

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.


3

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).


3

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.


Inoltre, penso che dal momento che utilizzo il CTE solo nel join, eseguo davvero il CTE solo una volta nella mia query, quindi la memorizzazione nella cache dei risultati non è stata un grosso problema in questo senso
acquista il

1

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.


1

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.


1

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

1
La tua risposta sembra essere molto generica ... Come si misura quella "tabella Temp superata CTE"? Hai delle misurazioni del tempo? Secondo me dovresti modificare la tua risposta e aggiungere maggiori dettagli.
Il Vic,

Sì, ho misurazioni del tempo e piano di esecuzione per supportare la mia affermazione.
Amardeep Kohli,

Impossibile aggiungere img per il piano di esecuzione a causa di privilegi limitati. Aggiornerà i dettagli una volta che è stato risolto
Amardeep Kohli
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.