Differenza tra CTE e SubQuery?


143

Da questo post Come utilizzare ROW_NUMBER nella seguente procedura?

Esistono due versioni di risposte in cui una utilizza a sub-querye l'altra utilizza a CTEper risolvere lo stesso problema.

Ora, quindi, qual è il vantaggio di utilizzare una CTE (Common Table Expression)"sottoquery" over (quindi, più leggibile ciò che la query sta effettivamente facendo)

L'unico vantaggio dell'utilizzo di un CTEover sub-selectè che posso effettivamente nominare il sub-query. Ci sono altre differenze tra questi due quando un CTE viene utilizzato come un semplice CTE (non ricorsivo)?


Domanda derivata con buona discussione: stackoverflow.com/q/11169550/781695
utente

7
IMO, chiunque pensi che un CTE sia meno leggibile del fatto che una gigantesca massa di sottoquery intrecciate non abbia visto la spazzatura di domande confuse a forma di dente di sega in uso nella maggior parte dei sistemi di gestione dei dati aziendali. Le query di grandi dimensioni e non banali sono in genere drammaticamente più facili da leggere in seguito o da nuovi occhi rispetto alle subquery, e almeno nel caso di Postgres magicamente ottengono prestazioni molto migliori in molti casi. ([Per motivi non ho ancora capito [( stackoverflow.com/questions/33731068/… ), poiché il contrario sembra più probabile.)
zxq9

Risposte:


102

Nelle versioni CTE sub-query vs semplici (non ricorsive), sono probabilmente molto simili. Dovresti utilizzare il profiler e il piano di esecuzione effettivo per individuare eventuali differenze, e questo sarebbe specifico per la tua configurazione (quindi non possiamo dirti la risposta per intero).

In generale ; Un CTE può essere utilizzato in modo ricorsivo; una query secondaria non può. Questo li rende particolarmente adatti alle strutture ad albero.


1
Mi dispiace, avrei dovuto essere più chiaro nella mia domanda. Quale sarebbe la differenza tra CTE e sottoquery nel contesto in cui CTE viene usato come sottoquery?
dance2die,

2
@Marc Gravell: Possiamo fare di più però, dato che il comportamento del profiler non è garantito, rispetto al comportamento del CTE, che è (in termini di valutazione).
casperOne

1
Non sono sicuro di quanto questa affermazione abbia senso per le persone che osservano la differenza tra CTS e subquery - A CTE can be used recursively; a sub-query cannot. Un esempio sarebbe stato fantastico.
Aniket Thakur,

88

Il vantaggio principale di Common Table Expression (quando non lo si utilizza per query ricorsive ) è l'incapsulamento, invece di dover dichiarare la sottoquery in ogni luogo in cui si desidera utilizzarla, è possibile definirla una volta, ma avere più riferimenti ad esso.

Tuttavia, ciò non significa che venga eseguito una sola volta (come da precedenti iterazioni di questa risposta , grazie a tutti quelli che hanno commentato). La query ha sicuramente il potenziale per essere eseguita più volte se referenziata più volte; Query Optimizer prende infine la decisione su come interpretare il CTE.


"Pensa a un CTE come una variabile della tabella temporanea" significa che CTE è archiviato nel disco o nella memoria?
dance2die,

Non è possibile utilizzare il CTE o la subquery in più query, per definizione. Sono abbastanza sicuro che l'ottimizzatore gestisca la subquery nello stesso modo in cui gestirà il CTE (valutando il set di risultati solo una volta, indipendentemente da quante volte viene utilizzato all'interno della query 1)
AlexCuse

@AlexCuse: Penso di aver chiarito abbastanza il contesto del CTE, ma ne ho aggiunti altri per cercare di chiarire di più.
casperOne

@AlexCuse: non è inoltre implicito che CTE o subquery possano essere utilizzati in più punti. La differenza tra il CTE e l'ottimizzatore è che il comportamento del CTE è garantito, mentre il comportamento dell'ottimizzatore non lo è.
casperOne

e ammetterò che potrebbero esserci alcuni casi limite in cui l'ottimizzatore soffoca e la subquery viene valutata più di una volta, ma non mi sono imbattuto in nessun caso. Poi di nuovo, uso CTE ovunque possibile;)
AlexCuse

15

CTEsono più utili per la ricorsione:

WITH hier(cnt) AS (
        SELECT  1
        UNION ALL
        SELECT  cnt + 1
        FROM    hier
        WHERE   cnt < @n
        )
SELECT  cnt
FROM    hier

restituirà le @nrighe (fino a 101). Utile per calendari, set di righe fittizi ecc.

Sono anche più leggibili (secondo me).

A parte questo, sono CTEe subqueriessono identici.


In MSSQL, è necessario aggiungere un punto e virgola (;) prima di WITH, nell'ordine si otterrà un errore. dovrebbe essere;WITH blabla AS ...)
Obinna Nnenanya il

2
@ObinnaNnenanya: solo se non è la prima istruzione nel batch. Terminare le sue dichiarazioni con un punto e virgola è comunque una buona idea, anche se SQL Server non applica nelle versioni correnti di altri rispetto a prima WITH, MERGEe simili
Quassnoi

10

Una differenza che non è stata menzionata è che un singolo CTE può essere referenziato nelle diverse parti di un sindacato


8

A meno che non mi manchi qualcosa, puoi nominare CTE e subquery altrettanto facilmente.

Immagino che la differenza principale sia la leggibilità (trovo il CTE più leggibile perché definisce la tua subquery in anticipo piuttosto che nel mezzo).

E se hai bisogno di fare qualcosa con la ricorsione, avrai un po 'di problemi a farlo con una subquery;)


1
Non sono sicuro che ci sia alcuna differenza non estetica (anche se mi aspetto che in alcune situazioni possano esserci lievi differenze nel piano di esecuzione). Vuoi illuminarmi?
AlexCuse

2
È possibile nominare CTE, ma è possibile solo alias sottoquery. La differenza è che puoi riutilizzare i CTE con più alias (vedi l'esempio di @Michael Petito nel suo commento a casperOne). Non conosco alcun modo per farlo con le subquery.
kmote

7

Un fatto importante che nessuno ha menzionato è che (almeno nei postgres), i CTE sono recinzioni di ottimizzazione:

https://blog.2ndquadrant.com/postgresql-ctes-are-optimization-fences/

Cioè, saranno trattati come la propria query atomica, piuttosto che piegati nell'intero piano di query. Non ho le competenze per fornire una spiegazione migliore, ma dovresti controllare la semantica per la versione di sql che stai usando; per utenti esperti, essere in grado di creare un recinto di ottimizzazione può aiutare le prestazioni se si è esperti nel controllo del pianificatore di query; nel 99% dei casi, tuttavia, dovresti evitare di provare a dire al pianificatore di query cosa fare, perché ciò che pensi sarà più veloce è probabilmente peggiore di quello che pensa sarà più veloce. :-)


6

Aggiungendo alle risposte degli altri, se si utilizza più volte la stessa sottoquery, è possibile sostituire tutte queste sottoquery con un CTE. Ciò ti consente di riutilizzare meglio il codice.


4

Una cosa che devi anche capire è che nelle versioni precedenti di SQL Server (sì, molte persone devono ancora supportare i database di SQL Server 2000), i CTE non sono ammessi e quindi la tabella derivata è la soluzione migliore.


2

SUGGERIMENTO: (MAXRECURSION n)

puoi limitare il numero di livelli di ricorsione consentiti per un'istruzione specifica utilizzando il MAXRECURSIONsuggerimento e un valore compreso tra 0 e 32.767 nella OPTIONclausola

Ad esempio, puoi provare:

OPTION 
      (MAXRECURSION 150)

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