8

Ich habe eine Tabellenwert-UDF geschrieben, die von einem CTE gestartet wird, 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.SQL Server CTE in Self-Joins verwiesen langsam

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

Die Abfrage ist sehr komplex, aber hier ist eine vereinfachte pseudo-Version davon

WITH DataCTE as 
(
    SELECT [columns] FROM table 
         INNER JOIN table2 
         ON [...] 

         INNER JOIN table3 
         ON [...] 

         LEFT JOIN table3 
         ON [...] 
) 
SELECT [aggregates_columns of each subset] FROM DataCTE Main 
LEFT JOIN DataCTE BananasSubset 
       ON [...] 
      AND Product = 'Bananas' 
      AND Quality = 100 
LEFT JOIN DataCTE DamagedBananasSubset 
       ON [...] 
      AND Product = 'Bananas' 
      AND Quality < 20 
LEFT JOIN DataCTE MangosSubset 
       ON [...] 
GROUP BY [ 

Ich habe das Gefühl, dass SQL Server durcheinander und ruft den CTE für jeden selbst verbinden, die an von der Suche bestätigt scheint der Ausführungsplan, obwohl ich gestehe, kein Experte darin zu sein, diese zu lesen.

Ich hätte angenommen, dass SQL Server intelligent genug ist, die Datenabfrage 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 die select select-Abfrage wie im CTE verwendet, aber es stattdessen in eine temporäre Tabelle ausgegeben.

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 Tabellenwerte ist, so dass ich alles in einer einzigen Aussage 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

+0

Können Sie Ihren Ausführungsplan posten? –

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.

Related reading:

Zitat aus dem letzten Link:

Die zugrunde liegende Abfrage CTE wird aufgerufen jedes Mal, wenn es in die unmittelbar folgende Abfrage referenziert wird.

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

UPDATE:

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

Einige Gedanken:

  • können Sie eine gespeicherte Prozedur anstelle eines UDF verwenden (anstelle von innen nicht)?
  • Dies ist möglicherweise nicht möglich, aber wenn Sie die left join von Ihrem CTE entfernen können, könnten Sie das in eine indizierte Sicht verschieben. Wenn Sie dazu in der Lage sind, können Sie sogar Leistungssteigerungen gegenüber der temporären Tabelle feststellen.
+0

Vielen Dank für diese tollen Referenzen. Das ist, was ich dann angenommen habe ... Ich werde Eleganz fallen lassen müssen, wie Sie sagen, diese UDF dauert 40 Sekunden ist keine Option. Ich hoffe, es wird in einer nächsten Version von SQL Server optimiert werden, aber ... Bis dahin werde ich wahrscheinlich zu vermeiden CTEs ... Zumindest mit einer temporären Tabelle kann ich mehr fühlen Kontrolle darüber, was hinter den Kulissen vor sich geht. Danke nochmal. –

+0

Argh ... Ich hatte vergessen, dass selbst die Multi-UDF nicht temporäre Tabellen verwenden kann. Ich habe versucht, stattdessen Tabellenvariablen verwenden, aber die Leistung ist absolut schrecklich ... sogar schlechter als als CTE-Version ... Meine Datenteilmenge ist etwa 10 000 Zeilen, kann aber bis zu 100 000 je nach Parametern von der geliefert werden Benutzer. Was sind meine anderen Optionen, wenn ich bedenke, dass ich meine Daten als Tabelle an den Anrufer zurückgeben muss. Danke. –

+0

Siehe mein Update. Leider habe ich das Gefühl, dass keiner von denen für dich arbeiten wird. –

Verwandte Themen