Was ist der Unterschied zwischen einem CTE und einer Temp-Tabelle?

174

Was ist der Unterschied zwischen einem Common Table Expression (CTE) und einer temporären Tabelle? Und wann soll ich eins übereinander verwenden?

CTE

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

SELECT * FROM cte

Temp-Tabelle

SELECT Column1, Column2, Column3
INTO #tmpTable
FROM SomeTable

SELECT * FROM #tmpTable
Rachel
quelle

Antworten:

200

Das ist ziemlich weit gefasst, aber ich werde Ihnen so allgemein wie möglich antworten.

CTEs ...

  • Nicht indizierbar sind (aber vorhandene Indizes für referenzierte Objekte verwenden können)
  • Kann keine Einschränkungen haben
  • Sind im Wesentlichen Einweg VIEWs
  • Besteht nur so lange, bis die nächste Abfrage ausgeführt wird
  • Kann rekursiv sein
  • Keine dedizierten Statistiken (stützen Sie sich auf Statistiken der zugrunde liegenden Objekte)

#Temp Tables ...

  • Sind echte materialisierte Tabellen, die in Tempdb existieren
  • Kann indiziert werden
  • Kann Einschränkungen haben
  • Bestehen Sie für das Leben der aktuellen VERBINDUNG
  • Kann von anderen Abfragen oder Unterprozeduren referenziert werden
  • Lassen Sie sich vom Motor eigene Statistiken erstellen

Sie haben sehr unterschiedliche Anwendungsfälle. Wenn Sie eine sehr große Ergebnismenge haben oder mehrmals darauf verweisen müssen, schreiben Sie sie in eine #tempTabelle. Wenn es rekursiv sein muss, wegwerfbar ist oder nur etwas logisch vereinfachen soll, CTEwird a bevorzugt.

Außerdem CTEsollte niemals a für die Aufführung verwendet werden . Mit einem CTE werden Sie die Dinge so gut wie nie beschleunigen, da es sich wiederum nur um eine Einwegansicht handelt. Sie können einige nette Dinge mit ihnen machen, aber das Beschleunigen einer Abfrage ist nicht wirklich eine davon.

JNK
quelle
Eine große MERGE mit CTE zu beschleunigen ist eine Sache
AgentFire
1
Das Beschleunigen vieler Abfragen mithilfe von CTEs ist auch eine Sache, da Sie mit CTEs Ihre eigenen Geschäftskenntnisse hinzufügen können, um den Abfrageoptimierer zu übertreffen. Beispielsweise können Sie Teil 1 Ihres CTE aus Tabellen auswählen lassen, bei denen Sie wissen, dass die resultierenden Zeilen sehr klein sind. In derselben Abfrage können Sie diese winzige Ergebnismenge mit einer größeren Ergebnismenge verknüpfen und Probleme, die durch veraltete Statistiken usw. verursacht wurden, vollständig umgehen. Dazu müssen Sie Abfragehinweise hinzufügen, um die Reihenfolge zu erzwingen. Es funktioniert, es verbessert die Leistung.
Dave Hilditch
"nie für die Darbietung verwendet werden" ist eine breite und etwas subjektive Aussage, obwohl ich Ihren Punkt verstehe. Zusätzlich zu den anderen Kommentaren kann jedoch ein weiterer potenzieller Leistungsgewinn durch die Verwendung eines CTE auftreten, wenn von einer anderen Form der Rekursion wie rekursiven Prozeduraufrufen oder einem Cursor zu einem rekursiven CTE gewechselt wird.
JD
29

BEARBEITEN:

Bitte beachten Sie Martins Kommentare unten:

Der CTE wird nicht als Tabelle im Speicher gespeichert. Es ist nur eine Möglichkeit, eine Abfragedefinition zu kapseln. Im Falle des OP wird es eingeblendet und genauso, wie es gerade getan wird SELECT Column1, Column2, Column3 FROM SomeTable. Meistens werden sie nicht im Voraus materialisiert, weshalb dies keine Zeilen zurückgibt. WITH T(X) AS (SELECT NEWID())SELECT * FROM T T1 JOIN T T2 ON T1.X=T2.XÜberprüfen Sie auch die Ausführungspläne. Obwohl es manchmal möglich ist, den Plan zu hacken, um eine Spule zu bekommen. Es gibt ein Verbindungselement, das einen Hinweis dazu anfordert. - Martin Smith 15. Februar 12 um 17.08 Uhr


Ursprüngliche Antwort

CTE

Lesen Sie mehr über MSDN

Ein CTE erstellt die im Speicher verwendete Tabelle, ist jedoch nur für die darauf folgende spezifische Abfrage gültig. Bei Verwendung der Rekursion kann dies eine effektive Struktur sein.

Möglicherweise möchten Sie auch eine Tabellenvariable verwenden. Dies wird als temporäre Tabelle verwendet und kann mehrmals verwendet werden, ohne dass für jeden Join eine erneute Materialisierung erforderlich ist. Wenn Sie jetzt ein paar Datensätze beibehalten müssen, nach der nächsten Auswahl ein paar weitere Datensätze hinzufügen, nach einer weiteren Operation ein paar weitere Datensätze hinzufügen und dann nur eine Handvoll Datensätze zurückgeben möchten, kann dies eine praktische Struktur sein, wie es nicht der Fall ist muss nach der Ausführung nicht gelöscht werden. Meist nur syntaktischer Zucker. Wenn Sie jedoch die Zeilenanzahl niedrig halten, wird sie niemals auf der Festplatte gespeichert. Siehe Was ist der Unterschied zwischen einer temporären Tabelle und einer Tabellenvariablen in SQL Server? für mehr Details.

Temp-Tabelle

Lesen Sie mehr über MSDN - Scrollen Sie etwa 40% des Weges nach unten

Eine temporäre Tabelle ist im wahrsten Sinne des Wortes eine Tabelle, die auf der Festplatte erstellt wurde und nur in einer bestimmten Datenbank gelöscht werden kann, von der jeder weiß, dass sie gelöscht werden kann. Es liegt in der Verantwortung eines guten Entwicklers, diese Tabellen zu zerstören, wenn sie nicht mehr benötigt werden. Ein DBA kann sie jedoch auch löschen.

Temporäre Tabellen gibt es in zwei Varianten: lokal und global. In Bezug auf MS SQL Server verwenden Sie eine #tableNameBezeichnung für lokal und eine ##tableNameBezeichnung für global (beachten Sie die Verwendung eines einfachen oder doppelten # als identifizierendes Merkmal).

Beachten Sie, dass Sie mit temporären Tabellen im Gegensatz zu Tabellenvariablen oder CTE Indizes und dergleichen anwenden können, da dies im normalen Sinne des Wortes legitime Tabellen sind.


Im Allgemeinen würde ich temporäre Tabellen für längere oder größere Abfragen und CTEs oder Tabellenvariablen verwenden, wenn ich bereits einen kleinen Datensatz hätte und einfach schnell ein bisschen Code für etwas Kleines schreiben wollte. Die Erfahrung und der Rat anderer deuten darauf hin, dass Sie CTEs verwenden sollten, wenn Sie eine geringe Anzahl von Zeilen zurückgegeben haben. Wenn Sie eine große Anzahl haben, würden Sie wahrscheinlich von der Möglichkeit profitieren, die temporäre Tabelle zu indizieren.

jcolebrand
quelle
11
Der CTE wird nicht als Tabelle im Speicher gespeichert. Es ist nur eine Möglichkeit, eine Abfragedefinition zu kapseln. Im Falle des OP wird es eingebettet und genauso wie geradeSELECT Column1, Column2, Column3 FROM SomeTable
Martin Smith
4
Meistens werden sie nicht im Voraus materialisiert, weshalb dies keine Zeilen zurückgibt. WITH T(X) AS (SELECT NEWID())SELECT * FROM T T1 JOIN T T2 ON T1.X=T2.XÜberprüfen Sie auch die Ausführungspläne. Obwohl es manchmal möglich ist, den Plan zu hacken , um eine Spule zu bekommen. Es gibt ein Verbindungselement , das einen Hinweis dazu anfordert.
Martin Smith
16

Die akzeptierte Antwort hier lautet: "Ein CTE sollte niemals für die Leistung verwendet werden" - aber das könnte irreführen. Im Zusammenhang mit CTEs im Vergleich zu temporären Tabellen habe ich gerade eine Menge Junk aus einer Reihe gespeicherter Prozesse entfernt, weil einige Doofus gedacht haben müssen, dass die Verwendung temporärer Tabellen nur wenig oder gar keinen Aufwand verursacht. Ich habe das Los in CTEs verschoben, mit Ausnahme derer, die während des gesamten Prozesses legitimerweise wiederverwendet werden sollten. Ich habe nach allen Messwerten etwa 20% an Leistung gewonnen. Ich habe mich dann daran gemacht, alle Cursor zu entfernen, die versucht haben, eine rekursive Verarbeitung zu implementieren. Hier habe ich den größten Gewinn gesehen. Am Ende habe ich die Antwortzeiten um den Faktor zehn verkürzt.

CTEs und Temp-Tabellen haben sehr unterschiedliche Anwendungsfälle. Ich möchte nur betonen, dass das Verständnis und die korrekte Verwendung von CTEs zwar kein Allheilmittel sind, aber zu einigen wirklich herausragenden Verbesserungen sowohl in Bezug auf die Codequalität / Wartbarkeit als auch in Bezug auf die Geschwindigkeit führen können. Seit ich sie in den Griff bekommen habe, sehe ich temporäre Tabellen und Cursor als das große Übel der SQL-Verarbeitung. Ich komme jetzt mit Tabellenvariablen und CTEs für fast alles zurecht. Mein Code ist sauberer und schneller.

Mel Padden
quelle
Jetzt lasst uns fair sein - Cursor sind das große Übel; temporäre Tische sind im schlimmsten Fall ein geringeres Übel. :-) Es ist wirklich unfair, sie auf das gleiche Niveau zu bringen, wie du es selbst gesehen hast.
RDFozz
@RDFozz richtig, die Hölle hat 9 Kreise, wie wir alle wissen . Setzen wir Temp-Tabellen auf 2nd und Cursor auf ... 7.? ;)
ypercubeᵀᴹ
1
Wissen Sie, was das "große Übel" in der Programmierung ist? Wenn Leute sagen, dass eine bestimmte Technik böse ist. Es gibt einen Platz für Cursor. In bestimmten Szenarien können sie andere Techniken übertreffen. Hier gibt es nichts Böses - Sie müssen lernen, das richtige Werkzeug für den Job zu verwenden. Messen Sie, was Sie tun, und glauben Sie nicht, dass der Hype um CTE, Temp Tables oder Cursors böse ist. Messen - weil die Wahrheit vom Szenario abhängt.
Dave Hilditch
@ DaveHilditch, das ist ein fairer Kommentar, aber es ist auch ein fairer Kommentar, um zu behaupten, dass Cursor in sehr, sehr vielen Situationen nicht die richtige Lösung sind, so dass es eine praktikable Verallgemeinerung ist, sie als auch fast einen letzten Ausweg zu haben.
Mel Padden
1
Nach meiner Erfahrung ist ein CURSOR an sich nicht schlecht. CURSORS werden von Entwicklern im Allgemeinen "falsch" verwendet, da Sie in den meisten Programmiersprachen iterativ denken müssen, im Gegensatz zu SQL, wo Sie meistens in Stapeln denken müssen. Ich weiß, dass dies ein häufiger Fehler an meinem Arbeitsplatz ist, bei dem Entwickler einen anderen Ausweg aus einem Problem als mit einem CURSOR nicht "erkennen" können. Deshalb ist ein guter DBA nützlich, um sie zu lehren und zu korrigieren. @ DaveHilditch ist absolut richtig: Das richtige Werkzeug für den richtigen Job ist alles, was es braucht.
Philippe
14

Ein CTE kann innerhalb einer Abfrage wiederholt aufgerufen werden und wird jedes Mal ausgewertet, wenn auf ihn verwiesen wird. Dieser Prozess kann rekursiv sein. Wird es nur einmal referenziert, verhält es sich ähnlich wie eine Unterabfrage, obwohl CTEs parametriert werden können.

Eine temporäre Tabelle wird physisch beibehalten und kann indiziert werden. In der Praxis kann es auch vorkommen, dass das Abfrageoptimierungsprogramm die Ergebnisse von Zwischenverknüpfungen oder Unterabfragen hinter den Kulissen beibehält, z.

IIRC-Tabellenvariablen sind dagegen immer speicherinterne Strukturen.

Betroffen vonTunbridgeWells
quelle
4
CTEs können parametriert werden? Wie? Tabellenvariablen sind nicht immer speicherinterne Strukturen. Siehe Martins ausgezeichnete Antwort auf eine verwandte Frage.
Paul White
11

Die temporäre Tabelle ist ein echtes Objekt in tempdb, aber cte ist nur eine Art Wrapper für komplexe Abfragen, um die Syntax der Organisationsrekursion in einem Schritt zu vereinfachen.

Oleg Dok
quelle
8

Der Hauptgrund für die Verwendung von CTEs ist der Zugriff auf Fensterfunktionen wie row_number()und verschiedene andere.

Dies bedeutet, dass Sie Dinge tun können, wie die erste oder letzte Reihe pro Gruppe SEHR SEHR schnell und effizient zu erhalten - in den meisten praktischen Fällen effizienter als andere Mittel .

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

Sie können eine ähnliche Abfrage wie oben mithilfe einer korrelierten Unterabfrage oder mithilfe einer Unterabfrage ausführen, der CTE ist jedoch in fast allen Szenarien schneller.

Darüber hinaus können CTEs dabei helfen, Ihren Code zu vereinfachen. Dies kann zu Leistungsverbesserungen führen, da Sie die Abfrage besser verstehen und mehr Geschäftslogik einführen können, um dem Optimierer zu helfen, selektiver zu sein.

Darüber hinaus können CTEs die Leistung steigern, wenn Sie Ihre Geschäftslogik verstehen und wissen, welche Teile der Abfrage zuerst ausgeführt werden sollen. Stellen Sie in der Regel Ihre selektivsten Abfragen an die erste Stelle, um Ergebnismengen zu erhalten, die beim nächsten Join einen Index verwenden können, und fügen Sie die option(force order)Abfrage hinzu Hinweis

Schließlich verwenden CTEs standardmäßig kein Tempdb, sodass Sie die Konflikte mit diesem Engpass durch deren Verwendung reduzieren.

Temporäre Tabellen sollten verwendet werden, wenn Sie die Daten mehrmals abfragen müssen, oder wenn Sie Ihre Abfragen messen und feststellen, dass durch Einfügen in eine temporäre Tabelle und anschließendes Hinzufügen eines Indexes Ihre Leistung verbessert wird.

Dave Hilditch
quelle
alle guten Punkte ... +1
Mel Padden
6

Hier scheint es ein bisschen Negativität gegenüber CTEs zu geben.

Mein Verständnis eines CTE ist, dass es sich im Grunde genommen um eine Art Ad-hoc-Sicht handelt. SQL ist sowohl eine deklarative als auch eine satzbasierte Sprache. CTEs sind eine großartige Möglichkeit, einen Satz zu deklarieren! Einen CTE nicht indizieren zu können, ist eigentlich eine gute Sache, weil Sie es nicht müssen! Es ist wirklich eine Art syntaktischer Zucker, der das Lesen und Schreiben der Abfrage erleichtert. Jeder anständige Optimierer ermittelt den besten Zugriffsplan anhand von Indizes für die zugrunde liegenden Tabellen. Dies bedeutet, dass Sie Ihre CTE-Abfrage effektiv beschleunigen können, indem Sie den Indexhinweisen für die zugrunde liegenden Tabellen folgen.

Nur weil Sie eine Menge als CTE definiert haben, bedeutet dies nicht, dass alle Zeilen in der Menge verarbeitet werden müssen. Abhängig von der Abfrage verarbeitet das Optimierungsprogramm möglicherweise "gerade genug" Zeilen, um die Abfrage zu erfüllen. Vielleicht brauchten Sie nur die ersten 20 oder so für Ihren Bildschirm. Wenn Sie eine temporäre Tabelle erstellt haben, müssen Sie wirklich alle diese Zeilen lesen / schreiben!

Aufgrund dessen würde ich sagen, dass CTEs eine großartige Funktion von SQL sind und überall dort verwendet werden können, wo sie die Lesbarkeit der Abfrage verbessern. Ich würde nur über eine temporäre Tabelle für einen Stapelprozess nachdenken, der wirklich jeden einzelnen Datensatz verarbeiten müsste. Selbst dann ist es nicht wirklich empfehlenswert, da es für die Datenbank in einer temporären Tabelle weitaus schwieriger ist, Sie bei der Zwischenspeicherung und den Indizes zu unterstützen. Es ist möglicherweise besser, eine permanente Tabelle mit einem PK-Feld zu haben, das für Ihre Transaktion eindeutig ist.

Ich muss zugeben, dass ich hauptsächlich Erfahrung mit DB2 habe. Daher gehe ich davon aus, dass CTE in beiden Produkten auf ähnliche Weise funktioniert. Ich werde gerne korrigiert stehen, wenn CTEs in SQL Server irgendwie minderwertig sind. ;)

Ben Thurley
quelle