SQL Server CTE, auf den in Self-Joins verwiesen wird, langsam

8

Ich habe eine Tabellenwert-UDF geschrieben, die mit einem CTE beginnt, um eine Teilmenge der Zeilen aus einer großen Tabelle zurückzugeben. Es gibt mehrere Joins im CTE. Ein paar innere und eine linke verbinden sich mit anderen Tabellen, die nicht viele Zeilen enthalten. Das CTE hat eine WHERE-Klausel, die die Zeilen innerhalb eines Datumsbereichs zurückgibt, um nur die benötigten Zeilen zurückzugeben.

Ich referenziere dann dieses CTE in 4 selbst links Joins, um Zwischensummen mit verschiedenen Kriterien zu erstellen.

Die Abfrage ist ziemlich komplex, aber hier ist eine vereinfachte Pseudoversion davon

%Vor%

Ich habe das Gefühl, dass SQL Server verwirrt wird und den CTE für jeden Self-Join aufruft, was durch einen Blick auf den Ausführungsplan bestätigt scheint, obwohl ich gestehe, dass ich kein Experte darin bin, diese zu lesen.

Ich hätte angenommen, dass SQL Server schlau genug ist, um den Datenabruf nur einmal vom CTE durchzuführen, anstatt es mehrmals zu tun.

Ich habe den gleichen Ansatz versucht, aber anstatt ein CTE zu verwenden, um die Teilmenge der Daten zu erhalten, habe ich dieselbe SELECT-Abfrage wie im CTE verwendet, aber stattdessen die Ausgabe in eine temporäre Tabelle vorgenommen.

Die Version, die sich auf die CTE-Version bezieht, dauert 40 Sekunden. Die Version, die sich auf die temporäre Tabelle bezieht, dauert zwischen 1 und 2 Sekunden.

Warum ist SQL Server nicht intelligent genug, um die CTE-Ergebnisse im Speicher zu halten?

Ich mag CTEs, besonders in diesem Fall, da meine UDF eine Tabellenwert ist, so dass ich alles in einer einzigen Anweisung behalten konnte.

Um eine temporäre Tabelle zu verwenden, müsste ich eine UDF-Tabelle mit mehreren Anweisungen schreiben, die ich etwas weniger elegant finde.

Hatten einige von Ihnen solche Leistungsprobleme mit CTE, und wenn ja, wie haben Sie sie sortiert?

Danke,

Kharlos

    
Kharlos Dominguez 16.06.2010, 15:39
quelle

1 Antwort

6

Ich glaube, dass CTE-Ergebnisse jedes Mal abgerufen werden. Bei einer temporären Tabelle werden die Ergebnisse gespeichert, bis sie gelöscht werden. Dies scheint die Leistungsgewinne zu erklären, die Sie beim Wechsel zu einer temporären Tabelle gesehen haben.

Ein weiterer Vorteil ist, dass Sie Indizes für eine temporäre Tabelle erstellen können, die Sie mit einer CTE nicht ausführen können. Nicht sicher, ob es in Ihrer Situation einen Vorteil geben würde, aber es ist gut zu wissen.

Weiterführende Literatur:

Zitat vom letzten Link:

  

Die zugrundeliegende Abfrage des CTE wird sein   jedes Mal aufgerufen, wenn es referenziert wird   die unmittelbar folgende Abfrage.

Ich würde sagen, gehen Sie mit der Temp-Tabelle. Leider ist Eleganz nicht immer die beste Lösung.

UPDATE:

Hmmm, das macht die Dinge schwieriger. Es fällt mir schwer, das zu sagen, ohne die ganze Umgebung zu betrachten.

Einige Gedanken:

  • können Sie eine gespeicherte Prozedur anstelle einer UDF verwenden (statt von innen)?
  • Dies ist möglicherweise nicht möglich, aber wenn Sie left join von Ihrem CTE entfernen können, können Sie dies in eine indizierte Sicht verschieben. Wenn Sie dazu in der Lage sind, können Sie Leistungssteigerungen sogar gegenüber der temporären Tabelle feststellen.
Abe Miessler 16.06.2010, 15:45
quelle