Qual è la differenza tra una tabella CTE e una tabella temporanea?


174

Qual è la differenza tra una Common Table Expression (CTE) e una tabella temporanea? E quando dovrei usarne uno sopra l'altro?

CTE

WITH cte (Column1, Column2, Column3)
AS
(
    SELECT Column1, Column2, Column3
    FROM SomeTable
)

SELECT * FROM cte

Tabella temporanea

SELECT Column1, Column2, Column3
INTO #tmpTable
FROM SomeTable

SELECT * FROM #tmpTable


Risposte:


200

Questo è piuttosto ampio, ma ti darò una risposta il più generale possibile.

CTE ...

  • Non indicizzabili (ma possono utilizzare indici esistenti su oggetti referenziati)
  • Non possono avere vincoli
  • Sono essenzialmente usa VIEWe getta
  • Persiste solo fino all'esecuzione della query successiva
  • Può essere ricorsivo
  • Non hai statistiche dedicate (fai affidamento sulle statistiche sugli oggetti sottostanti)

#Tabelle temporali ...

  • Sono vere tabelle materializzate che esistono in tempdb
  • Può essere indicizzato
  • Può avere vincoli
  • Persistere per la vita dell'attuale CONNESSIONE
  • Può essere referenziato da altre query o sottoprocedure
  • Hanno statistiche dedicate generate dal motore

Per quanto riguarda quando usarli, hanno casi d'uso molto diversi. Se hai un set di risultati molto grande o devi fare riferimento ad esso più di una volta, mettilo in una #temptabella. Se deve essere ricorsivo, è usa e getta o è solo per semplificare qualcosa logicamente, CTEsi preferisce a.

Inoltre, nonCTE dovrebbe mai essere usato per le prestazioni . Non accelererai quasi mai le cose usando un CTE, perché, di nuovo, è solo una vista usa e getta. Puoi fare alcune cose pulite con loro, ma accelerare una query non è davvero uno di questi.


accelerare un grosso MERGE usando CTE è una cosa
AgentFire

1
Accelerare molte query utilizzando CTE è anche una cosa perché con CTE è possibile aggiungere le proprie conoscenze aziendali per superare le prestazioni di Query Optimizer. Ad esempio, puoi avere la parte 1 della tua selezione CTE dalle tabelle in cui sai che le righe risultanti saranno molto piccole. All'interno della stessa query, è possibile unire questo minuscolo gruppo di risultati a un gruppo di risultati più ampio e bypassare completamente i problemi causati da statistiche obsolete, ecc. Per fare ciò, è necessario aggiungere suggerimenti di query per forzare l'ordine. Funziona, migliora le prestazioni.
Dave Hilditch,

"Non essere mai usato per la performance" è un'affermazione ampia e in qualche modo soggettiva, anche se capisco il tuo punto. Sebbene, oltre agli altri commenti, un altro potenziale guadagno in termini di prestazioni derivante dall'uso di un CTE può verificarsi quando si passa a un CTE ricorsivo da un'altra forma di ricorsione come chiamate di procedura ricorsive o un cursore.
JD

29

MODIFICARE:

Si prega di vedere i commenti di Martin di seguito:

Il CTE non si materializza come una tabella in memoria. È solo un modo per incapsulare una definizione di query. Nel caso dell'OP sarà integrato e lo stesso che farebbe SELECT Column1, Column2, Column3 FROM SomeTable. Il più delle volte non si materializzano in anticipo, motivo per cui questo non restituisce righe WITH T(X) AS (SELECT NEWID())SELECT * FROM T T1 JOIN T T2 ON T1.X=T2.X, controlla anche i piani di esecuzione. Anche se a volte è possibile hackerare il piano per ottenere una bobina. C'è un elemento di connessione che richiede un suggerimento per questo. - Martin Smith, 15 febbraio 12 alle 17:08


Risposta originale

CTE

Ulteriori informazioni su MSDN

Un CTE crea la tabella utilizzata in memoria, ma è valida solo per la query specifica che la segue. Quando si utilizza la ricorsione, questa può essere una struttura efficace.

Potresti anche prendere in considerazione l'utilizzo di una variabile di tabella. Viene utilizzato come tabella temporanea e può essere utilizzato più volte senza necessità di essere nuovamente materializzato per ogni join. Inoltre, se è necessario persistere alcuni record ora, aggiungere alcuni altri record dopo la selezione successiva, aggiungere alcuni altri record dopo un'altra operazione, quindi restituire solo quei pochi record, quindi questa può essere una struttura pratica, poiché non non è necessario lasciarlo cadere dopo l'esecuzione. Principalmente solo zucchero sintattico. Tuttavia, se si mantiene basso il conteggio delle righe, non si materializza mai su disco. Vedere Qual è la differenza tra una tabella temporanea e una variabile di tabella in SQL Server? per ulteriori dettagli.

Tabella temporanea

Ulteriori informazioni su MSDN: scorri verso il basso del 40% circa

Una tabella temporanea è letteralmente una tabella creata su disco, solo in un database specifico che tutti sanno che può essere eliminato. È responsabilità di un buon sviluppatore distruggere quei tavoli quando non sono più necessari, ma un DBA può anche cancellarli.

Le tabelle temporanee sono disponibili in due varietà: locale e globale. In termini di MS Sql Server si utilizza una #tableNamedesignazione per locale e una ##tableNamedesignazione per globale (si noti l'uso di un singolo o doppio # come caratteristica identificativa).

Si noti che con le tabelle temporanee, al contrario delle variabili di tabella o CTE, è possibile applicare indici e simili, poiché si tratta legittimamente di tabelle nel senso normale della parola.


Generalmente userei le tabelle temporanee per query più lunghe o più grandi, e CTE o variabili di tabella se avessi già un piccolo set di dati e volessi semplicemente scrivere un po 'di codice per qualcosa di piccolo. L'esperienza e i consigli di altri indicano che è necessario utilizzare CTE laddove si riceva un numero limitato di righe. Se hai un numero elevato, probabilmente trarrai vantaggio dalla possibilità di indicizzare nella tabella temporanea.


11
Il CTE non si materializza come una tabella in memoria. È solo un modo per incapsulare una definizione di query. Nel caso dell'OP sarà integrato e lo stesso che farebbeSELECT Column1, Column2, Column3 FROM SomeTable
Martin Smith il

4
Il più delle volte non si materializzano in anticipo, motivo per cui questo non restituisce righe WITH T(X) AS (SELECT NEWID())SELECT * FROM T T1 JOIN T T2 ON T1.X=T2.X, controlla anche i piani di esecuzione. Anche se a volte è possibile hackerare il piano per ottenere una bobina. C'è un elemento di connessione che richiede un suggerimento per questo.
Martin Smith,

16

La risposta accettata qui dice "un CTE non dovrebbe mai essere usato per le prestazioni" - ma ciò potrebbe fuorviare. Nel contesto dei CTE rispetto alle tabelle temporanee, ho appena finito di rimuovere una serie di spazzatura da una suite di processi archiviati perché alcuni doofus devono aver pensato che ci fosse poco o nessun sovraccarico nell'uso delle tabelle temporanee. Ho inserito il lotto nei CTE, ad eccezione di quelli che sarebbero stati legittimamente riutilizzati durante tutto il processo. Ho ottenuto circa il 20% di rendimento da tutte le metriche. Ho quindi iniziato a rimuovere tutti i cursori che stavano cercando di implementare l'elaborazione ricorsiva. Questo è dove ho visto il massimo guadagno. Ho finito per ridurre i tempi di risposta di un fattore dieci.

I CTE e le tabelle temporanee hanno casi d'uso molto diversi. Voglio solo sottolineare che, sebbene non sia una panacea, la comprensione e l'uso corretto dei CTE possono portare ad alcuni miglioramenti davvero stellari sia nella qualità / manutenibilità del codice che nella velocità. Da quando li ho presi, vedo le tabelle temporanee e i cursori come i grandi mali dell'elaborazione SQL. Ora riesco a cavarmela bene con variabili di tabella e CTE per quasi tutto. Il mio codice è più pulito e veloce.


Ora, siamo onesti: i cursori sono il grande male; le tabelle temporanee sono nel peggiore dei casi un male minore . :-) È davvero ingiusto metterli allo stesso livello, come ti sei visto.
RDFozz,

@RDFozz, l' inferno ha 9 cerchi, come tutti sappiamo . Mettiamo tabelle temporanee al 2 ° e cursori al ... 7 °? ;)
ypercubeᵀᴹ

1
Sai qual è il "grande male" nella programmazione? Quando la gente dice che una particolare tecnica è malvagia. C'è un posto per i cursori. Possono superare altre tecniche in determinati scenari. Non c'è niente di male qui: devi imparare ad usare lo strumento giusto per il lavoro. Misura ciò che stai facendo e non credere al clamore che i CTE, le tabelle temporanee o i cursori sono malvagi. Misura: perché la verità dipende dallo scenario.
Dave Hilditch,

@DaveHilditch è un commento giusto, ma è anche un commento corretto per affermare che in moltissime situazioni, i cursori non sono la soluzione giusta, quindi è una generalizzazione praticabile averli come, quasi un'ultima risorsa.
Mel Padden,

1
Nella mia esperienza, un CURSORE non è male in sé. I CURSORI sono comunemente "erroneamente" utilizzati dagli sviluppatori perché nella maggior parte dei linguaggi di programmazione, devi pensare in modo iterativo, al contrario di SQL, dove devi pensare principalmente in batch. So che questo è un errore comune sul mio posto di lavoro in cui gli sviluppatori non riescono a "vedere" una via d'uscita da un problema diverso da un CURSORE, quindi perché un buon DBA è utile per insegnarli e correggerli. @DaveHilditch ha perfettamente ragione: lo strumento giusto per il lavoro giusto è tutto ciò che serve.
Philippe,

14

Un CTE può essere chiamato ripetutamente all'interno di una query e viene valutato ogni volta che viene referenziato: questo processo può essere ricorsivo. Se viene fatto riferimento una sola volta, si comporta in modo molto simile a una query secondaria, sebbene i CTE possano essere parametrizzati.

Una tabella temporanea è fisicamente persistente e può essere indicizzata. In pratica, Query Optimizer può anche persistere risultati intermedi di join o query secondarie dietro le quinte, ad esempio nelle operazioni di spooling, quindi non è strettamente vero che i risultati dei CTE non vengono mai mantenuti su disco.

Le variabili della tabella IIRC (d'altra parte) sono sempre strutture in memoria.


4
I CTE possono essere parametrizzati? Come? Inoltre, le variabili di tabella non sono sempre strutture in memoria. Vedi l' eccellente risposta di Martin a una domanda correlata.
Paul White

11

La tabella temporanea è un oggetto reale in tempdb, ma cte è solo un tipo di wrapper attorno a query complesse per semplificare la sintassi dell'organizzazione della ricorsione in un solo passaggio.


8

Il motivo principale per utilizzare i CTE è accedere alle funzioni della finestra come row_number()e varie altre.

Ciò significa che puoi fare cose come ottenere la prima o l'ultima riga per gruppo MOLTO MOLTO in modo rapido ed efficiente - più efficiente di altri mezzi nella maggior parte dei casi pratici .

with reallyfastcte as (
select *, 
row_number() over (partition by groupingcolumn order by sortingcolumn) as rownum
from sometable
)
select *
from reallyfastcte
where rownum = 1;

È possibile eseguire una query simile alla precedente utilizzando una query secondaria correlata o utilizzando una query secondaria ma il CTE sarà più veloce in quasi tutti gli scenari.

Inoltre, i CTE possono davvero aiutare a semplificare il tuo codice. Questo può portare a miglioramenti delle prestazioni perché comprendi di più la query e puoi introdurre più logica di business per aiutare l'ottimizzatore a essere più selettivo.

Inoltre, i CTE possono migliorare le prestazioni se capisci la tua logica aziendale e sai quali parti della query devono essere eseguite per prime, in genere metti le tue query più selettive al primo posto che portano a set di risultati che possono usare un indice nel loro prossimo join e aggiungere la option(force order)query suggerimento

Infine, i CTE non usano tempdb di default, quindi riduci la contesa su quel collo di bottiglia attraverso il loro uso.

Le tabelle temporanee devono essere utilizzate se è necessario eseguire una query dei dati più volte o, in alternativa, se si misurano le query e si scopre che inserendo in una tabella temporanea e quindi aggiungendo un indice per migliorare le prestazioni.


tutti i punti positivi ... +1
Mel Padden

6

Sembra esserci un po 'di negatività qui nei confronti di CTE.

La mia comprensione di un CTE è che è fondamentalmente una specie di visione ad hoc. SQL è un linguaggio sia dichiarativo che basato su set. I CTE sono un ottimo modo per dichiarare un set! Non essere in grado di indicizzare un CTE è in realtà una buona cosa perché non è necessario! È davvero una specie di zucchero sintattico per facilitare la lettura / scrittura della query. Qualsiasi ottimizzatore decente elaborerà il miglior piano di accesso utilizzando gli indici nelle tabelle sottostanti. Ciò significa che è possibile velocizzare efficacemente la query CTE seguendo i consigli sull'indice nelle tabelle sottostanti.

Inoltre, solo perché hai definito un set come CTE, ciò non significa che tutte le righe nel set debbano essere elaborate. A seconda della query, l'ottimizzatore potrebbe elaborare righe "appena sufficienti" per soddisfare la query. Forse hai solo bisogno dei primi 20 circa per il tuo schermo. Se hai creato una tabella temporanea, devi davvero leggere / scrivere tutte quelle righe!

Sulla base di questo direi che i CTE sono una grande funzionalità di SQL e possono essere utilizzati ovunque rendano più semplice la lettura della query. Vorrei solo pensare a una tabella temporanea per un processo batch che avrebbe davvero bisogno di elaborare ogni singolo record. Anche allora afaik non è davvero raccomandato perché su una tabella temporanea è molto più difficile per il database aiutarti con la cache e gli indici. Potrebbe essere meglio avere una tabella permanente con un campo PK univoco per la tua transazione.

Devo ammettere che la mia esperienza è principalmente con DB2, quindi presumo che il lavoro di CTE sia simile in entrambi i prodotti. Sarò felicemente corretto se i CTE sono in qualche modo inferiori nel server SQL. ;)

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.