Unterschied zwischen CTE und SubQuery?

143

Aus diesem Beitrag Wie verwende ich ROW_NUMBER im folgenden Verfahren?

Es gibt zwei Versionen von Antworten, bei denen eine a sub-queryund die andere a verwendet CTE, um dasselbe Problem zu lösen.

Was ist nun der Vorteil der Verwendung einer CTE (Common Table Expression)"Unterabfrage" (also besser lesbar, was die Abfrage tatsächlich tut) ?

Der einzige Vorteil der Verwendung eines CTEüber sub-selectist , dass ich wirklich kann nenne das sub-query. Gibt es andere Unterschiede zwischen diesen beiden, wenn ein CTE als einfacher (nicht rekursiver) CTE verwendet wird?

dance2die
quelle
Abgeleitete Frage mit guter Diskussion: stackoverflow.com/q/11169550/781695
Benutzer
7
IMO, jeder, der glaubt, ein CTE sei weniger lesbar, als dass ein riesiger Klumpen miteinander verwobener Unterabfragen den Müllhaufen verwirrender sägezahnförmiger Abfragen in den meisten Unternehmensdatenverwaltungssystemen nicht gesehen hätte. Große, nicht triviale Abfragen sind in der Regel später oder mit neuen Augen dramatisch leichter zu lesen als Unterabfragen, und zumindest bei Postgres ist die Leistung in vielen Fällen auf magische Weise viel besser. ([Aus Gründen, die ich noch nicht verstanden habe [( stackoverflow.com/questions/33731068/… ), da das Gegenteil wahrscheinlicher erscheint.)
zxq9

Antworten:

102

In der Unterabfrage gegenüber einfachen (nicht rekursiven) CTE-Versionen sind sie wahrscheinlich sehr ähnlich. Sie müssten den Profiler und den tatsächlichen Ausführungsplan verwenden, um Unterschiede zu erkennen. Dies ist spezifisch für Ihr Setup (daher können wir Ihnen die Antwort nicht vollständig mitteilen).

Im Allgemeinen ; Ein CTE kann rekursiv verwendet werden. Eine Unterabfrage kann nicht. Dadurch eignen sie sich besonders gut für Baumstrukturen.

Marc Gravell
quelle
1
Entschuldigung, ich hätte in meiner Frage klarer sein sollen. Was wäre der Unterschied zwischen CTE und Unterabfrage in dem Kontext, in dem CTE wie Unterabfrage verwendet wird?
Dance2die
2
@Marc Gravell: Wir können jedoch mehr als das tun, da das Verhalten des Profilers nicht garantiert ist, im Vergleich zum Verhalten des CTE (was die Bewertung betrifft).
casperOne
1
Ich bin mir nicht sicher, inwieweit diese Aussage für Personen, die sich mit CTS und Unterabfrageunterschieden befassen, sinnvoll ist A CTE can be used recursively; a sub-query cannot. Ein Beispiel wäre toll gewesen.
Aniket Thakur
88

Der Hauptvorteil des allgemeinen Tabellenausdrucks (wenn er nicht für rekursive Abfragen verwendet wird ) ist die Kapselung. Anstatt die Unterabfrage an jedem Ort deklarieren zu müssen, an dem Sie sie verwenden möchten, können Sie sie einmal definieren, haben jedoch mehrere Referenzen dazu.

Dies bedeutet jedoch nicht , dass es nur einmal ausgeführt wird (gemäß den vorherigen Iterationen dieser Antwort vielen Dank an alle, die dies kommentiert haben). Die Abfrage kann definitiv mehrfach ausgeführt werden, wenn mehrmals darauf verwiesen wird. Der Abfrageoptimierer trifft letztendlich die Entscheidung, wie der CTE interpretiert werden soll.

casperOne
quelle
"Stellen Sie sich einen CTE als temporäre Tabellenvariable vor" bedeutet dies, dass der CTE auf der Festplatte oder im Speicher gespeichert ist?
Dance2die
Sie können den CTE oder die Unterabfrage per Definition nicht in mehreren Abfragen verwenden. Ich bin mir ziemlich sicher, dass das Optimierungsprogramm die Unterabfrage genauso behandelt wie den CTE (Auswertung der Ergebnismenge nur einmal, unabhängig davon, wie oft sie in der 1-Abfrage verwendet wird)
AlexCuse
@AlexCuse: Ich denke, ich habe den Kontext des CTE ausreichend geklärt, aber ich habe mehr hinzugefügt, um mehr zu klären.
casperOne
@AlexCuse: Es gibt auch keine Implikation, dass der CTE oder die Unterabfrage an mehreren Stellen verwendet werden kann. Der Unterschied zwischen dem CTE und dem Optimierer besteht jedoch darin, dass das Verhalten des CTE garantiert ist, während dies beim Verhalten des Optimierers nicht der Fall ist.
casperOne
und ich werde zugeben, dass es einige Randfälle geben könnte, in denen der Optimierer drosselt und die Unterabfrage mehr als einmal ausgewertet wird, aber ich bin auf keinen gestoßen.
Andererseits benutze
15

CTEsind am nützlichsten für die Rekursion:

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

gibt @nZeilen zurück (bis zu 101). Nützlich für Kalender, Dummy-Rowsets usw.

Sie sind auch besser lesbar (meiner Meinung nach).

Ansonsten sind CTEund subqueriesidentisch.

Quassnoi
quelle
In MSSQL müssen Sie vor WITH ein Semikolon (;) hinzufügen. In der Reihenfolge erhalten Sie eine Fehlermeldung. es sollte sein;WITH blabla AS ...)
Obinna Nnenanya
2
@ObinnaNnenanya: Nur wenn es nicht die erste Anweisung im Stapel ist. Beenden Sie Ihre Aussagen mit Semikolons ist eine gute Idee , wie auch immer, obwohl SQL Server erzwingt nicht in den aktuellen Versionen anderer als zuvor WITH, MERGEund ähnliche
Quassnoi
10

Ein Unterschied, der nicht erwähnt wurde, ist, dass ein einzelner CTE in den verschiedenen Teilen einer Gewerkschaft referenziert werden kann

user340140
quelle
8

Sofern mir nichts fehlt, können Sie CTEs und Unterabfragen genauso einfach benennen.

Ich denke, der Hauptunterschied ist die Lesbarkeit (ich finde den CTE besser lesbar, weil er Ihre Unterabfrage eher im Voraus als in der Mitte definiert).

Und wenn Sie etwas mit Rekursion tun müssen, werden Sie ein bisschen Probleme haben, dies mit einer Unterabfrage zu tun;)

AlexCuse
quelle
1
Ich bin mir nicht sicher, ob es einen nicht-ästhetischen Unterschied gibt (obwohl ich davon ausgehe, dass es in bestimmten Situationen geringfügige Unterschiede im Ausführungsplan geben kann). Möchtest du mich aufklären?
AlexCuse
2
Sie können nennen CTEs, aber man kann nur alias Subqueries. Der Unterschied besteht darin, dass Sie CTEs mit mehreren Aliasen wiederverwenden können (vgl. Das Beispiel von @Michael Petito in seinem Kommentar zu casperOne). Ich kenne keine Möglichkeit, dies mit Unterabfragen zu tun.
kmote
7

Eine wichtige Tatsache, die niemand erwähnt hat, ist, dass CTEs (zumindest in Postgres) Optimierungszäune sind:

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

Das heißt, sie werden als ihre eigene atomare Abfrage behandelt und nicht in den gesamten Abfrageplan gefaltet. Mir fehlt das Fachwissen, um eine bessere Erklärung zu geben, aber Sie sollten die Semantik für die von Ihnen verwendete SQL-Version überprüfen. Für fortgeschrittene Benutzer kann die Möglichkeit, einen Optimierungszaun zu erstellen, die Leistung verbessern, wenn Sie Experten in der Steuerung des Abfrageplaners sind. In 99% der Fälle sollten Sie jedoch vermeiden, dem Abfrageplaner mitzuteilen, was zu tun ist, da das, was Sie für schneller halten, wahrscheinlich schlechter ist als das, was er für schneller hält. :-)

Ajax
quelle
6

Wenn Sie zu den Antworten anderer hinzufügen und ein und dieselbe Unterabfrage mehrmals verwendet haben, können Sie alle diese Unterabfragen durch einen CTE ersetzen. Auf diese Weise können Sie Ihren Code besser wiederverwenden.

AK
quelle
4

Eine Sache, die Sie auch verstehen müssen, ist, dass in älteren Versionen von SQL Server (ja, viele Leute müssen noch SQL Server 2000-Datenbanken unterstützen) CTEs nicht zulässig sind und die abgeleitete Tabelle dann Ihre beste Lösung ist.

HLGEM
quelle
2

TIPP: (MAXRECURSION n)

Sie können die Anzahl der für eine bestimmte Anweisung zulässigen Rekursionsstufen begrenzen, indem Sie den MAXRECURSIONHinweis und einen Wert zwischen 0 und 32.767 in der OPTIONKlausel verwenden

Zum Beispiel könnten Sie versuchen:

OPTION 
      (MAXRECURSION 150)

GO
Basic_
quelle