Vantaggi di Common Table Expression (CTE)?


21

Da msdn :

A differenza di una tabella derivata, un CTE può essere autoreferenziale e può essere referenziato più volte nella stessa query.

Sto usando un sacco di CTE, ma non ho mai riflettuto a fondo sui vantaggi di usarli.

Se faccio riferimento a un CTE più volte nella stessa query:

  • C'è qualche vantaggio in termini di prestazioni?
  • Se eseguo un self join, SQL Server eseguirà la scansione delle tabelle di destinazione due volte?

2
Profiler dovrebbe dirti se esegue la scansione due volte. IMHO, i CTE sono fantastici per la ricorsione.
Dan Andrews,

3
Non ci sono risposte concrete quando Query Optimizer è in gioco. Alcune query vedranno vantaggi in termini di prestazioni, altre no. A volte l'utilizzo di una tabella temporanea anziché di un CTE sarà più veloce, a volte no.

Risposte:


25

Di norma, un CTE non migliorerà MAI le prestazioni .

Un CTE è essenzialmente una vista usa e getta. Non ci sono statistiche aggiuntive memorizzate, nessun indice, ecc. Funziona come una scorciatoia per una sottoquery.

Secondo me possono essere FACILMENTE abusati (vedo molti abusi nel codice nel mio lavoro). Alcune buone risposte sono qui, ma se devi fare riferimento a qualcosa più di una volta, o è più di qualche centinaio di migliaia di righe, mettilo invece in una #temptabella e indicizzalo.


3
Essere d'accordo. Fatta eccezione per i CTE ricorsivi, aiutano semplicemente la leggibilità
gbn

Cosa succede se il CTE restituisce solo poche righe (in modo che possano essere conservate in memoria) che sono costose da calcolare (aggregazione su una tabella di grandi dimensioni) e che il risultato viene utilizzato più di una volta? Ciò dovrebbe migliorare le prestazioni, non è vero? (almeno questa è la mia esperienza con PostgreSQL e Oracle in cui la tabella temporanea viene utilizzata molto raramente)
a_horse_with_no_name

2
@a_horse_with_no_name - equivarrebbe a renderlo una sottoquery. Se il risultato viene utilizzato più di una volta in una singola query, verrà riutilizzato e non ricalcolato. Se viene utilizzato in più di una query, allora CTEè una cattiva scelta poiché i risultati vengono scartati dopo la prima query.
JNK,

@JNK: grazie. Sembra che SQL Server si comporti diversamente qui.
a_horse_with_no_name il

Alcune persone trovano di CTE più leggibile in determinate circostanze FWIW stackoverflow.com/a/11170918/32453
rogerdpack

14

Un punto oltre alla ricorsione in cui trovo le CTE incredibilmente utili è la creazione di query di reporting complesse. Uso una serie di CTE per ottenere pezzi dei dati di cui ho bisogno e quindi combinarli nella selezione finale. Trovo che siano più facili da mantenere rispetto a fare la stessa cosa con molte tabelle derivate o 20 join e trovo che posso essere più sicuro che restituisce i dati corretti senza alcun effetto di più record a causa delle numerose relazioni in tutti i diversi join. Lasciami fare un rapido esempio:

;WITH Conferences (Conference_id)
AS 
(select  m.Conference_id
FROM mydb.dbo.Conference m 
WHERE client_id = 10
    and Conference_id in 
            (select Conference_id from mydb.dbo.Expense 
            where amount <>0
            and amount is not null)
     )
--select * from Conferences
,MealEaters(NumberMealEaters, Conference_id, AttendeeType)
AS
(Select count(*) as NumberMealEaters, m.Conference_id,  AttendeeType 
from mydb.dbo.attendance ma 
join Conferences m on m.Conference_id = ma.Conference_id
where (ma.meals_consumed>0 or meals_consumed is null)and attended = 1
group by m.Conference_id)
--select * from MealEaters

,Expenses (Conference_id,expense_date, expenseDescription,  RecordIdentifier,amount)
AS
(select Conference_id,max(expense_date) as Expense_date, expenseDescription,  RecordIdentifier,sum(amount) as amount
    FROM
        (SELECT Conference_id,expense_date,  amount, RecordIdentifier
        FROM mydb.dbo.Expense
        WHERE  amount <> 0 
            and Conference_id IN 
            (SELECT  Conference_id
            FROM mydb.dbo.Conferences ) 
        group by Conference_id, RecordIdentifier) a
)
--select * from Expenses
Select m.Conference_id,me.NumberMealEaters, me.AttendeeType, e.expense_date,         e.RecordIdentifier,amount
from Conferences m
join mealeaters me on m.Conference_id = me.Conference_id
join expenses e on e.Conference_id = m.Conference_id

Quindi separando i diversi blocchi di informazioni che desideri, puoi controllare ogni parte individualmente (usando le selezioni commentate, decommentando ognuna individualmente e correndo solo fino a quella selezionata) e se hai bisogno di modificare la spesa calcolo (in questo esempio), è più facile da trovare rispetto a quando sono tutti mescolati insieme in un'unica query di massa. Naturalmente le query di report effettive per le quali utilizzo questo sono generalmente molto più complicate dell'esempio.


1
Solo per la segnalazione di query? I sistemi su cui lavoro ogni giorno hanno query di transazione così complicate. Stranamente le nostre query sui rapporti sono spesso alcune delle nostre più semplici. (Escludendo le banali query CRUD senza join ovviamente).
Kevin Cathcart,

L'ho usato come esempio perché quelli in genere sono i più complicati qui
HLGEM

+1 a volte una query più logica (leggibile dall'uomo) è preferibile a una potenzialmente con prestazioni migliori.
giorno

Sì. Dato che un CTE di solito produce lo stesso piano risultante, non vedo alcun motivo per creare mostruosità orribilmente annidate, multi-subquery - quando potremmo invece disporre visivamente ogni componente nell'ordine in cui sono necessari. Importo file XML e eseguo varie acrobazie per ottenere i dati nella forma corretta, il che sarebbe insopportabile da scrivere / leggere senza CTE. (Alcuni dei miei vecchi codici hanno probabilmente terribili sottoquery a tutto tondo!)
underscore_d

0

Come sempre dipende ma ci sono casi in cui le prestazioni sono notevolmente migliorate. Lo vedo con le istruzioni INSERT INTO SELECT in cui si utilizza un CTE per la selezione e quindi lo si utilizza in INSERT INTO. Potrebbe avere a che fare con RCSI impostato per il database, ma per quei momenti in cui è selezionato pochissimo può aiutare parecchio.

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.