In dieser ausgezeichneten SO-Frage wurden Unterschiede zwischen CTE
und sub-queries
diskutiert.
Ich möchte speziell fragen:
Unter welchen Umständen ist jeder der folgenden Punkte effizienter / schneller?
- CTE
- Unterabfrage
- Temporäre Tabelle
- Tabellenvariable
Traditionell habe ich viel für die temp tables
Entwicklung verwendet stored procedures
- da sie lesbarer zu sein scheinen als viele miteinander verflochtene Unterabfragen.
Non-recursive CTE
s kapseln Datensätze sehr gut und sind sehr gut lesbar. Gibt es jedoch bestimmte Umstände, unter denen man sagen kann, dass sie immer eine bessere Leistung erbringen? oder muss man immer mit den verschiedenen Optionen herumspielen, um die effizienteste Lösung zu finden?
BEARBEITEN
Mir wurde kürzlich gesagt, dass temporäre Tabellen in Bezug auf die Effizienz eine gute erste Wahl sind, da ihnen ein Histogramm zugeordnet ist, dh Statistiken.
quelle
Antworten:
SQL ist eine deklarative Sprache, keine prozedurale Sprache. Das heißt, Sie erstellen eine SQL-Anweisung, um die gewünschten Ergebnisse zu beschreiben. Sie sagen der SQL-Engine nicht, wie sie die Arbeit erledigen soll.
In der Regel empfiehlt es sich, die SQL-Engine und den SQL-Optimierer den besten Abfrageplan finden zu lassen. Die Entwicklung einer SQL-Engine erfordert viele jahrelange Anstrengungen. Lassen Sie die Ingenieure also tun, was sie können.
Natürlich gibt es Situationen, in denen der Abfrageplan nicht optimal ist. Anschließend möchten Sie Abfragehinweise verwenden, die Abfrage umstrukturieren, Statistiken aktualisieren, temporäre Tabellen verwenden, Indizes hinzufügen usw., um eine bessere Leistung zu erzielen.
Wie für Ihre Frage. Die Leistung von CTEs und Unterabfragen sollte theoretisch gleich sein, da beide dem Abfrageoptimierer dieselben Informationen bereitstellen. Ein Unterschied besteht darin, dass ein mehr als einmal verwendeter CTE leicht identifiziert und einmal berechnet werden kann. Die Ergebnisse könnten dann mehrmals gespeichert und gelesen werden. Leider scheint SQL Server diese grundlegende Optimierungsmethode nicht zu nutzen (Sie können diese allgemeine Eliminierung von Unterabfragen nennen).
Temporäre Tabellen sind eine andere Sache, da Sie mehr Anleitungen zur Ausführung der Abfrage geben. Ein wesentlicher Unterschied besteht darin, dass das Optimierungsprogramm Statistiken aus der temporären Tabelle verwenden kann, um seinen Abfrageplan zu erstellen. Dies kann zu Leistungssteigerungen führen. Wenn Sie einen komplizierten CTE (Unterabfrage) haben, der mehrmals verwendet wird, führt das Speichern in einer temporären Tabelle häufig zu einer Leistungssteigerung. Die Abfrage wird nur einmal ausgeführt.
Die Antwort auf Ihre Frage lautet, dass Sie herumspielen müssen, um die erwartete Leistung zu erzielen, insbesondere bei komplexen Abfragen, die regelmäßig ausgeführt werden. In einer idealen Welt würde der Abfrageoptimierer den perfekten Ausführungspfad finden. Obwohl dies häufig der Fall ist, können Sie möglicherweise einen Weg finden, um eine bessere Leistung zu erzielen.
quelle
Es gibt keine Regel. Ich finde CTEs besser lesbar und verwende sie, es sei denn, sie weisen Leistungsprobleme auf. In diesem Fall untersuche ich das eigentliche Problem, anstatt zu vermuten, dass der CTE das Problem ist, und versuche, es mit einem anderen Ansatz neu zu schreiben. Das Problem hat normalerweise mehr zu bieten als die Art und Weise, wie ich meine Absichten mit der Abfrage deklarativ dargelegt habe.
Es gibt sicherlich Fälle, in denen Sie CTEs entwirren oder Unterabfragen entfernen und durch eine # temp-Tabelle ersetzen und die Dauer verkürzen können. Dies kann auf verschiedene Dinge zurückzuführen sein, wie z. B. veraltete Statistiken, die Unfähigkeit, sogar genaue Statistiken zu erhalten (z. B. das Verknüpfen mit einer Tabellenwertfunktion), Parallelität oder sogar die Unfähigkeit, aufgrund der Komplexität der Abfrage einen optimalen Plan zu generieren ( In diesem Fall kann das Aufbrechen dem Optimierer eine Kampfchance geben. Es gibt jedoch auch Fälle, in denen die mit der Erstellung einer # temp-Tabelle verbundenen E / A die anderen Leistungsaspekte überwiegen können, die eine bestimmte Planform mit einem CTE weniger attraktiv machen können.
Ganz ehrlich, es gibt viel zu viele Variablen, um eine "richtige" Antwort auf Ihre Frage zu geben. Es gibt keinen vorhersehbaren Weg zu wissen, wann eine Abfrage zugunsten des einen oder anderen Ansatzes kippen könnte - wissen Sie nur, dass theoretisch dieselbe Semantik für einen CTE oder eine einzelne Unterabfrage genau dieselbe ausführen sollte . Ich denke, Ihre Frage wäre wertvoller, wenn Sie einige Fälle präsentieren, in denen dies nicht zutrifft - es kann sein, dass Sie eine Einschränkung im Optimierer entdeckt haben (oder eine bekannte entdeckt haben), oder dass Ihre Abfragen nicht semantisch äquivalent sind oder dass eines ein Element enthält, das die Optimierung verhindert.
Daher würde ich vorschlagen, die Abfrage so zu schreiben, wie es Ihnen am natürlichsten erscheint, und nur dann abzuweichen, wenn Sie ein tatsächliches Leistungsproblem des Optimierers feststellen. Persönlich stufe ich sie als CTE und dann als Unterabfrage ein, wobei die Tabelle #temp das letzte Mittel ist.
quelle
link / edit / close / flag
Wenn zum Schließen der Frage Stimmen abgegeben wurden, sehen Sie,close (n)
won
die Anzahl der Benutzer steht, die zum Schließen Ihrer Frage abgestimmt haben. Wenn Sie auf den Link klicken, werden die Gründe angezeigt, aus denen diese Benutzer ausgewählt wurden.#temp ist materalisiert und CTE nicht.
CTE ist nur eine Syntax, also theoretisch nur eine Unterabfrage. Es wird ausgeführt. #temp ist materialisiert. Ein teurer CTE in einem Join, der viele Male ausgeführt wird, ist in einem #temp möglicherweise besser. Auf der anderen Seite, wenn es sich um eine einfache Auswertung handelt, die nicht ausgeführt wird, aber einige Male, dann ist der Overhead von #temp nicht wert.
Es gibt einige Leute auf SO, die keine Tabellenvariablen mögen, aber ich mag sie, da sie materialisiert und schneller zu erstellen sind als #temp. Es gibt Zeiten, in denen das Abfrageoptimierungsprogramm mit einem #temp im Vergleich zu einer Tabellenvariablen besser abschneidet.
Die Möglichkeit, eine PK für eine # temp- oder Tabellenvariable zu erstellen, bietet dem Abfrageoptimierer mehr Informationen als ein CTE (da Sie keine PK für einen CTE deklarieren können).
quelle
Nur zwei Dinge, die es meiner Meinung nach IMMER vorzuziehen machen, eine # Temp-Tabelle anstelle eines CTE zu verwenden, sind:
Sie können einem CTE keinen Primärschlüssel zuweisen, sodass die Daten, auf die der CTE zugreift, jeden der Indizes in den Tabellen des CTE durchlaufen müssen, anstatt nur auf die PK oder den Index in der temporären Tabelle zuzugreifen.
Da Sie einem CTE keine Einschränkungen, Indizes und Primärschlüssel hinzufügen können, sind diese anfälliger für eingeschlichene Fehler und fehlerhafte Daten.
-onedaywhen gestern
Hier ist ein Beispiel, in dem # table-Einschränkungen fehlerhafte Daten verhindern können, was bei CTEs nicht der Fall ist
quelle
ALWAYS
ist etwas zu weit aber danke für die antwort. In Bezug auf die Lesbarkeit kann die Verwendung von CTEs eine gute Sache sein.CHECK
Einschränkung, die sich auf mehrere Zeilen / Tabellen bezieht) nicht erlaubt). Können Sie ein Beispiel veröffentlichen, bei dem ein CTE einen Fehler aufweist, den das temporäre Tabellenäquivalent nicht aufweist?