it-swarm.com.de

Welche sind performanter, CTE oder temporäre Tabellen?

Welche sind performanter, CTE oder Temporary Tables?

126
Blankman

Ich würde sagen, sie sind unterschiedliche Konzepte, aber nicht zu unterschiedlich, um "Kreide und Käse" zu sagen.

  • Eine temporäre Tabelle eignet sich zur Wiederverwendung oder zum Durchführen mehrerer Verarbeitungsdurchläufe für einen Datensatz.

  • Ein CTE kann entweder zur Wiederverwendung oder zur einfachen Verbesserung der Lesbarkeit verwendet werden.
    Und wie eine Ansicht oder eine Inline-Tabelle kann eine bewertete Funktion auch wie ein Makro behandelt werden, das in der Hauptabfrage erweitert wird

  • Eine temporäre Tabelle ist eine andere Tabelle mit einigen Regeln für den Gültigkeitsbereich

Ich habe Procs dort gespeichert, wo ich beide verwende (und auch Tabellenvariablen)

62
gbn

Es hängt davon ab, ob.

Als allererstes

Was ist ein allgemeiner Tabellenausdruck?

Ein (nicht rekursiver) CTE wird sehr ähnlich wie andere Konstrukte behandelt, die in SQL Server auch als Inline-Tabellenausdrücke verwendet werden können. Abgeleitete Tabellen, Ansichten und Inline-Tabellenfunktionen. Beachten Sie, dass, während BOL sagt, dass ein CTE "als temporäre Ergebnismenge gedacht werden kann", dies eine rein logische Beschreibung ist. Meistens ist es nicht eigenständig materialisiert.

Was ist eine temporäre Tabelle?

Dies ist eine Sammlung von Zeilen, die auf Datenseiten in Tempdb gespeichert sind. Die Datenseiten können sich teilweise oder vollständig im Speicher befinden. Zusätzlich kann die temporäre Tabelle indiziert werden und Spaltenstatistiken enthalten.

Testdaten

CREATE TABLE T(A INT IDENTITY PRIMARY KEY, B INT , F CHAR(8000) NULL);

INSERT INTO T(B)
SELECT TOP (1000000)  0 + CAST(NEWID() AS BINARY(4))
FROM master..spt_values v1,
     master..spt_values v2;

Beispiel 1

WITH CTE1 AS
(
SELECT A,
       ABS(B) AS Abs_B,
       F
FROM T
)
SELECT *
FROM CTE1
WHERE A = 780

Plan 1

Beachten Sie, dass im obigen Plan CTE1 nicht erwähnt wird. Es greift nur direkt auf die Basistabellen zu und wird genauso behandelt wie

SELECT A,
       ABS(B) AS Abs_B,
       F
FROM   T
WHERE  A = 780 

Das Umschreiben durch Materialisieren des CTE in eine temporäre Zwischentabelle wäre hier massiv kontraproduktiv.

Materialisierung der CTE-Definition von

SELECT A,
       ABS(B) AS Abs_B,
       F
FROM T

Wenn Sie etwa 8 GB Daten in eine temporäre Tabelle kopieren möchten, müssen Sie immer noch Daten daraus auswählen.

Beispiel 2

WITH CTE2
     AS (SELECT *,
                ROW_NUMBER() OVER (ORDER BY A) AS RN
         FROM   T
         WHERE  B % 100000 = 0)
SELECT *
FROM   CTE2 T1
       CROSS APPLY (SELECT TOP (1) *
                    FROM   CTE2 T2
                    WHERE  T2.A > T1.A
                    ORDER  BY T2.A) CA 

Das obige Beispiel dauert auf meinem Computer ungefähr 4 Minuten.

Nur 15 Zeilen der 1.000.000 zufällig generierten Werte stimmen mit dem Prädikat überein, aber der teure Tabellenscan findet 16 Mal statt, um diese zu finden.

enter image description here

Dies wäre ein guter Kandidat für die Verwirklichung des Zwischenergebnisses. Das Umschreiben der entsprechenden temporären Tabelle dauerte 25 Sekunden.

INSERT INTO #T
SELECT *,
       ROW_NUMBER() OVER (ORDER BY A) AS RN
FROM   T
WHERE  B % 100000 = 0

SELECT *
FROM   #T T1
       CROSS APPLY (SELECT TOP (1) *
                    FROM   #T T2
                    WHERE  T2.A > T1.A
                    ORDER  BY T2.A) CA 

With Plan

Manchmal kann es nützlich sein, einen Teil einer Abfrage in einer temporären Tabelle zwischenzuspeichern, auch wenn diese nur einmal ausgewertet wird. Dann kann der Rest der Abfrage erneut kompiliert werden, wobei Statistiken über das materialisierte Ergebnis verwendet werden. Ein Beispiel für diesen Ansatz finden Sie im SQL Cat-Artikel Wann werden komplexe Abfragen aufgeschlüsselt? .

Unter bestimmten Umständen verwendet SQL Server einen Spool, um ein Zwischenergebnis zwischenzuspeichern, z. von einem CTE, und vermeiden, diesen Unterbaum neu bewerten zu müssen. Dies wird im (migrierten) Connect-Element beschrieben. Geben Sie einen Hinweis an, um eine Zwischenmaterialisierung von CTEs oder abgeleiteten Tabellen zu erzwingen. . Es werden jedoch keine Statistiken dazu erstellt, und selbst wenn die Anzahl der gespoolten Zeilen erheblich von der geschätzten Anzahl abweichen sollte, kann sich der aktuelle Ausführungsplan als Reaktion nicht dynamisch anpassen (zumindest in den aktuellen Versionen. Adaptive Abfragepläne sind möglicherweise in möglich die Zukunft).

162
Martin Smith

CTE hat seine Verwendung - wenn die Daten im CTE klein sind und sich die Lesbarkeit stark verbessert, wie dies bei rekursiven Tabellen der Fall ist. Die Leistung ist jedoch mit Sicherheit nicht besser als bei Tabellenvariablen, und wenn es sich um sehr große Tabellen handelt, übertreffen temporäre Tabellen den CTE erheblich. Dies liegt daran, dass Sie keine Indizes für einen CTE definieren können und wenn Sie eine große Datenmenge haben, die das Verknüpfen mit einer anderen Tabelle erfordert (CTE ist einfach wie ein Makro). Wenn Sie mehrere Tabellen mit jeweils Millionen Datensatzzeilen verbinden, ist die Leistung von CTE erheblich schlechter als die von temporären Tabellen.

47
CSW

Temporäre Tabellen befinden sich immer auf der Festplatte. Solange der CTE im Arbeitsspeicher gespeichert werden kann, ist er wahrscheinlich schneller (wie auch eine Tabellenvariable).

Wenn jedoch die Datenlast Ihres CTE (oder Ihrer temporären Tabellenvariablen) zu groß wird, werden sie auch auf der Festplatte gespeichert, sodass dies keinen großen Vorteil bietet.

Im Allgemeinen bevorzuge ich einen CTE gegenüber einem temporären Tisch, da er nach der Verwendung weg ist. Ich muss nicht darüber nachdenken, es explizit oder irgendetwas fallen zu lassen.

Also, keine klare Antwort am Ende, aber persönlich würde ich CTE gegenüber temporären Tabellen vorziehen.

32
marc_s

CTE nimmt keinen physischen Raum ein. Es ist nur eine Ergebnismenge, die wir mit join verwenden können.

Temporäre Tabellen sind temporär. Wir können Indizes und Nebenbedingungen wie normale Tabellen erstellen, für die wir alle Variablen definieren müssen.

Gültigkeitsbereich der temporären Tabelle nur innerhalb der Sitzung. EX: Öffnen Sie zwei SQL-Abfragefenster

create table #temp(empid int,empname varchar)
insert into #temp 
select 101,'xxx'

select * from #temp

Führen Sie diese Abfrage im ersten Fenster aus, und führen Sie dann die folgende Abfrage im zweiten Fenster aus. Sie können den Unterschied feststellen.

select * from #temp
6
selvaraj

Daher wurde die Abfrage, die ich optimieren sollte, mit zwei CTEs in SQL Server geschrieben. Es dauerte 28 Sekunden.

Ich habe zwei Minuten damit verbracht, sie in temporäre Tabellen zu konvertieren, und die Abfrage hat 3 Sekunden gedauert

Ich habe der temporären Tabelle auf dem Feld, auf dem sie verknüpft wurde, einen Index hinzugefügt und ihn auf 2 Sekunden reduziert

Drei Minuten Arbeit und jetzt läuft es 12x schneller, wenn CTE entfernt wird. Ich persönlich werde keine CTEs verwenden, die schwieriger zu debuggen sind.

Das Verrückte ist, dass die CTEs beide nur einmal verwendet wurden und sich immer noch als 50% schneller erwiesen, wenn ein Index auf sie gesetzt wurde.

5
Mark Monforti

Ich habe beides benutzt, aber in massiv komplexen Prozeduren war es immer besser, mit temporären Tabellen zu arbeiten und methodischer. CTEs haben ihre Verwendung, aber im Allgemeinen mit kleinen Daten.

Zum Beispiel habe ich Sprocs erstellt, die innerhalb von 15 Sekunden Ergebnisse umfangreicher Berechnungen liefern, diesen Code jedoch so konvertieren, dass er in einem CTE ausgeführt wird. Dabei wurde eine Laufzeit von mehr als 8 Minuten festgestellt, um die gleichen Ergebnisse zu erzielen.

4
Andy_RC

Eine Verwendung, bei der ich CTEs herausragende Leistung fand, war die, bei der ich eine relativ komplexe Abfrage für einige Tabellen mit jeweils einigen Millionen Zeilen erstellen musste.

Ich habe den CTE verwendet, um zuerst die Teilmenge basierend auf den indizierten Spalten auszuwählen, um diese Tabellen zunächst auf jeweils einige tausend relevante Zeilen zu reduzieren und dann den CTE mit meiner Hauptabfrage zu verknüpfen. Dies hat die Laufzeit meiner Abfrage exponentiell verkürzt.

Während die Ergebnisse für den CTE nicht zwischengespeichert werden und Tabellenvariablen eine bessere Wahl gewesen sein könnten, wollte ich sie eigentlich nur ausprobieren und fand, dass sie zum obigen Szenario passen.

3
purchas

Spät zur Party, aber ...

Die Umgebung, in der ich arbeite, ist stark eingeschränkt. Einige Produkte von Anbietern werden unterstützt, und es werden Mehrwertdienste wie Berichterstellung bereitgestellt. Aufgrund von Richtlinien- und Vertragsbeschränkungen ist mir normalerweise der Luxus eines separaten Tabellen-/Datenbereichs und/oder der Möglichkeit, permanenten Code zu erstellen, nicht gestattet [je nach Anwendung wird es ein wenig besser].

IOW, I kann nicht normalerweise eine gespeicherte Prozedur oder UDFs oder temporäre Tabellen entwickeln usw. Ich muss so ziemlich alles über MEINE Anwendungsschnittstelle erledigen (Crystal Reports - Tabellen hinzufügen/verknüpfen, Where-Klauseln setzen) w/in CR usw.). Eine kleine Rettung ist, dass Crystal mir erlaubt, BEFEHLE (sowie SQL-Ausdrücke) zu verwenden. Einige Dinge, die durch die regulären Funktionen zum Hinzufügen/Verknüpfen von Tabellen nicht effizient sind, können durch Definieren eines SQL-Befehls ausgeführt werden. Ich benutze CTEs dadurch und habe sehr gute Ergebnisse "aus der Ferne" bekommen. CTEs helfen auch bei der Berichtwartung, da kein Code entwickelt und an einen DBA übergeben werden muss, um Tests auf mehreren Ebenen zu kompilieren, zu verschlüsseln, zu übertragen, zu installieren und anschließend zu erfordern. Ich kann CTEs über die lokale Schnittstelle durchführen.

Der Nachteil bei der Verwendung von CTEs mit CR ist, dass jeder Bericht separat ist. Jeder CTE muss für jeden Bericht gepflegt werden. Wo ich SPs und UDFs erstellen kann, kann ich etwas entwickeln, das von mehreren Berichten verwendet werden kann. Dazu muss nur eine Verknüpfung mit SP und die Übergabe von Parametern erfolgen, als ob Sie an einer regulären Tabelle arbeiten würden. CR ist Die Verarbeitung von Parametern in SQL-Befehlen ist nicht besonders gut, daher kann der Aspekt des CR/CTE-Aspekts fehlen. In diesen Fällen versuche ich normalerweise, den CTE zu definieren, um genügend Daten (aber nicht ALLE Daten) zurückzugeben, und dann den Datensatz zu verwenden Auswahlmöglichkeiten in CR, um das zu schneiden und zu würfeln.

Also ... ich stimme für CTEs (bis ich meinen Datenraum bekomme).

3
Marc

Dies ist eine wirklich offene Frage, und alles hängt davon ab, wie sie verwendet wird und von der Art der temporären Tabelle (Tabellenvariable oder traditionelle Tabelle).

In einer herkömmlichen temporären Tabelle werden die Daten in der temporären Datenbank gespeichert, wodurch die temporären Tabellen verlangsamt werden. Tabellenvariablen tun dies jedoch nicht.

1
JoshBerke

Aufgrund meiner Erfahrung mit SQL Server habe ich eines der Szenarien gefunden, in denen CTE eine Outperformance gegenüber der Temp-Tabelle aufwies

Ich musste ein DataSet (~ 100000) aus einer komplexen Abfrage nur EINMAL in meiner gespeicherten Prozedur verwenden.

  • Die temporäre Tabelle verursachte einen Overhead bei SQL, bei dem meine Prozedur nur langsam ausgeführt wurde (da temporäre Tabellen reale materialisierte Tabellen sind, die für die Lebensdauer meiner aktuellen Prozedur in Tempdb und Persist vorhanden sind).

  • Auf der anderen Seite bleibt CTE bei CTE nur so lange bestehen, bis die folgende Abfrage ausgeführt wird. CTE ist also eine praktische In-Memory-Struktur mit begrenztem Geltungsbereich. CTEs verwenden standardmäßig kein Tempdb.

Dies ist ein Szenario, in dem CTEs wirklich dazu beitragen können, Ihren Code zu vereinfachen und die Temp-Tabelle zu übertreffen. Ich hatte 2 CTEs verwendet, so etwas wie

WITH CTE1(ID, Name, Display) 
AS (SELECT ID,Name,Display from Table1 where <Some Condition>),
CTE2(ID,Name,<col3>) AS (SELECT ID, Name,<> FROM CTE1 INNER JOIN Table2 <Some Condition>)
SELECT CTE2.ID,CTE2.<col3>
FROM CTE2
GO
1
Amardeep Kohli

Ich habe dies gerade getestet - sowohl CTE als auch Nicht-CTE (wobei die Abfrage für jede Gewerkschaftsinstanz ausgefüllt wurde) dauerten beide ~ 31 Sekunden. CTE hat die Lesbarkeit des Codes erheblich verbessert. Reduzieren Sie den Code von 241 auf 130 Zeilen, was sehr gut ist. Temp-Tabelle auf der anderen Seite schnitt es auf 132 Zeilen und dauerte fünf Sekunden, um zu laufen. Kein Witz. Alle diese Tests wurden zwischengespeichert - die Abfragen wurden alle zuvor mehrmals ausgeführt.

1
user2989981