INSERT-Leistungsunterschied zwischen temporären Tabellen und Tabellenvariablen

12

Ich habe das folgende Problem in SQL Server 2005: Der Versuch, einige Zeilen in eine Tabellenvariable einzufügen, nimmt viel Zeit in Anspruch, verglichen mit derselben Einfügung mithilfe einer temporären Tabelle.

Dies ist der Code, der in die Tabellenvariable eingefügt werden soll

DECLARE @Data TABLE(...)
INSERT INTO @DATA( ... )
SELECT ..
FROM ...

Dies ist der Code, der in die temporäre Tabelle eingefügt werden soll

CREATE #Data TABLE(...)
INSERT INTO #DATA( ... )
SELECT ..
FROM ...
DROP TABLE #Data

Die temporäre Tabelle hat keine Schlüssel oder Indizes, der Auswahlbereich ist zwischen den beiden Abfragen identisch, und die Anzahl der von der Auswahl zurückgegebenen Ergebnisse beträgt ~ 10000 Zeilen. Die Zeit, die benötigt wird, um die Auswahl alleine auszuführen, beträgt ~ 10 Sekunden.

Die Ausführung der temporären Tabellenversion dauert bis zu 10 Sekunden. Ich musste die Tabellenvariablenversion nach 5 Minuten stoppen.

Ich muss eine Tabellenvariable verwenden, da die Abfrage Teil einer Tabellenwertfunktion ist, die keinen Zugriff auf temporäre Tabellen ermöglicht.

Ausführungsplan für die Tabellenvariablenversion Ausführungsplan

Ausführungsplan für die temporäre Tabellenversion Ausführungsplan

Munissor
quelle

Antworten:

8

Der offensichtliche Unterschied zwischen den beiden Plänen besteht darin, dass der schnelle parallel und der langsamere seriell ist.

Dies ist eine der Einschränkungen von Plänen, die in Tabellenvariablen eingefügt werden. Wie in den Kommentaren erwähnt (und es scheint, als hätte es den gewünschten Effekt), könnten Sie es versuchen

INSERT INTO @DATA ( ... ) 
EXEC('SELECT .. FROM ...')

um zu sehen, ob dies die Einschränkung umgeht.

Martin Smith
quelle
Es war ein großartiger Vorschlag, obwohl ich dachte, dass Sie EXECfür eine Funktion nicht verwenden können ... ich glaube, ich habe mich geirrt
Lamak
1
@ Lamak - Doh! Sie können nicht, so wird dies nicht für das OP funktionieren. Invalid use of a side-effecting operator 'INSERT EXEC' within a function.. Die OPENQUERYUmgehung könnte jedoch funktionieren.
Martin Smith
Ah, gut zu wissen, danke für die Klarstellung
Lamak
2
Als allgemeine Faustregel sollten Sie keine Tabellenvariablen verwenden, wenn Sie erwarten, dass ein großer Datenbestand zurückgegeben wird. Temp-Tabellen sind in diesem Fall normalerweise schneller.
HLGEM
1
@munissor, dann verwende keine Tabellenwertfunktion. Wenn Sie einen besseren Rat wünschen, schreiben Sie genau, was Sie tun.
HLGEM
-1

Tabellenvariablen sind manchmal langsamer, da es keine Statistiken zu Tabellenvariablen gibt und der Optimierer daher immer nur einen Datensatz annimmt.

Ich kann jedoch nicht garantieren, dass dies hier der Fall ist. Sie müssen die Informationen zu den "geschätzten Zeilen" im Abfrageplan für die Tabellenvariable überprüfen.

yoel halb
quelle
Wie würde sich das auf eine Einfügung in eine Tabellenvariable auswirken?
Martin Smith
Das scheint so zu sein, wie Sie sehen, gibt es nicht nur einen Unterschied zwischen parallelen und seriellen, sondern auch zwischen Hash- und Nested-Loop-Joins. Anscheinend geht der Optimierer davon aus, dass die Tabellenvariable einen Datensatz im Gedächtnis hat und das Ergebnis der Abfrage wird auch ein Datensatz sein. Dies ist wiederum die einzige Möglichkeit, um zu beweisen, dass die tatsächlichen Statistiken für jeden Teil der Abfrage angezeigt werden. Fakt ist jedoch, dass alle Abfragen mit Tabellenvariablen zu Schleifenverknüpfungen und serieller Verarbeitung führen. also ich
denke