Wie (und warum) wirkt sich TOP auf einen Ausführungsplan aus?

35

Bei einer mäßig komplexen Abfrage, die ich optimieren möchte, ist mir aufgefallen, dass das Entfernen der TOP nKlausel den Ausführungsplan ändert. Ich hätte gedacht, dass, wenn eine Abfrage TOP ndas Datenbankmodul enthält , die Abfrage ausgeführt wird, wobei die TOPKlausel ignoriert wird , und am Ende das Ergebnis auf die Anzahl n der angeforderten Zeilen reduziert wird. Der grafische Ausführungsplan scheint darauf hinzuweisen, dass dies der Fall ist - dies TOPist der "letzte" Schritt. Aber es scheint, dass mehr los ist.

Meine Frage ist, wie (und warum) sich eine TOP n-Klausel auf den Ausführungsplan einer Abfrage auswirkt.

Hier ist eine vereinfachte Version dessen, was in meinem Fall vor sich geht:

Die Abfrage stimmt mit Zeilen aus zwei Tabellen, A und B, überein.

Ohne die TOPKlausel werden nach Schätzungen des Optimierers 19.000 Zeilen aus Tabelle A und 46.000 Zeilen aus Tabelle B zurückgegeben. Die tatsächliche Anzahl der zurückgegebenen Zeilen beträgt 16.000 für A und 13.000 für B. Diese beiden Ergebnismengen werden für a mit einer Hash-Übereinstimmung verknüpft Insgesamt 69 Zeilen (dann wird eine Sortierung angewendet). Diese Abfrage erfolgt sehr schnell.

Wenn ich hinzufüge, verwendet TOP 1001der Optimierer keine Hash-Übereinstimmung. anstatt es sortiert zunächst die Ergebnisse aus Tabelle A (gleiche Schätzwert / Ist von 19k / 16k) und macht eine verschachtelte Schleife gegen Tabelle B Die geschätzte Anzahl der Zeilen für Tabelle B versteht sich nun auf 1, und das Merkwürdige ist , dass die TOP ndirekt die Auswirkungen geschätzte Anzahl von Ausführungen (Indexsuche) gegen B - es scheint immer 2n + 1 zu sein , oder in meinem Fall 2003. Diese Schätzung ändert sich entsprechend, wenn ich mich ändere TOP n. Da dies ein verschachtelter Join ist, beträgt die tatsächliche Anzahl der Ausführungen 16.000 (die Anzahl der Zeilen aus Tabelle A), was die Abfrage verlangsamt.

Das eigentliche Szenario ist etwas komplexer, aber dies erfasst die Grundidee / das grundlegende Verhalten. Beide Tabellen werden mit Indexsuchen durchsucht. Dies ist die SQL Server 2008 R2 Enterprise Edition.

David
quelle
Die Abfrage enthält eine ORDER BYKlausel. Hinzufügen von TOPÄnderungen, wo im Plan diese Art auftritt, aber ich bin mehr besorgt darüber, wie sich dies auf die Anzahl der Ausführungen von Index-Suchvorgängen in Tabelle B auswirkt ... (natürlich können die beiden verwandt sein - ich weiß nicht)
David
1
Verwandte Diskussion: der FAST num_rowsAbfragehinweis.
Remus Rusanu

Antworten:

38

Ich hätte gedacht, dass, wenn eine Abfrage TOP n enthält, das Datenbankmodul die Abfrage ausführen würde, wobei die TOP-Klausel ignoriert würde, und dann am Ende das Ergebnis auf die Anzahl n der angeforderten Zeilen verkleinern würde. Der grafische Ausführungsplan scheint darauf hinzuweisen, dass dies der Fall ist - TOP ist der "letzte" Schritt. Aber es scheint, dass mehr los ist.

Die Art und Weise, wie das oben Gesagte formuliert ist, lässt mich denken, dass Sie möglicherweise ein falsches Bild davon haben, wie eine Abfrage ausgeführt wird. Ein Operator in einem Abfrageplan ist kein Schritt (bei dem die vollständige Ergebnismenge eines vorherigen Schritts von der nächsten ausgewertet wird).

SQL Server verwendet ein Pipeline- Ausführungsmodell, bei dem jeder Operator Methoden wie Init () , GetRow () und Close () verfügbar macht . Wie der Name GetRow () andeutet, erstellt ein Operator bei Bedarf jeweils eine Zeile (wie vom übergeordneten Operator gefordert). Dies ist in der Online-Dokumentation für logische und physische Operatoren dokumentiert. Weitere Informationen finden Sie in meinem Blog-Beitrag Warum Abfragepläne rückwärts ausgeführt werden . Dieses zeilenweise Modell ist für die Erstellung einer fundierten Intuition für die Ausführung von Abfragen von entscheidender Bedeutung.

Meine Frage ist, wie (und warum) sich eine TOPn-Klausel auf den Ausführungsplan einer Abfrage auswirkt.

Einige logische Operationen wie TOPSemi-Joins und der FAST n Abfragehinweis wirken sich auf die Art und Weise aus, wie das Abfrageoptimierungsprogramm Ausführungsplanalternativen kostet. Die Grundidee ist, dass eine mögliche Planform die ersten n Zeilen schneller zurückgibt als ein anderer Plan, der für die Rückgabe aller Zeilen optimiert wurde.

Beispielsweise ist der Join mit indizierten verschachtelten Schleifen häufig der schnellste Weg, um eine kleine Anzahl von Zeilen zurückzugeben, obwohl der Hash- oder Merge-Join mit Scans bei größeren Mengen möglicherweise effizienter ist. Das Abfrageoptimierungsprogramm ermittelt diese Auswahlmöglichkeiten, indem es ein Zeilenziel an einem bestimmten Punkt in der logischen Betriebsstruktur festlegt.

Ein Zeilenziel ändert die Art und Weise, in der Alternativen für Abfragepläne berechnet werden. Das Wesentliche dabei ist, dass das Optimierungsprogramm zunächst jeden Operator so kalkuliert, als ob die gesamte Ergebnismenge erforderlich wäre, ein Zeilenziel an der entsprechenden Stelle festlegt und dann den Planbaum zurücksetzt, um die Anzahl der zu untersuchenden Zeilen zu schätzen um das Reihenziel zu erreichen.

Beispielsweise setzt eine Logik TOP(10)an einem bestimmten Punkt in der logischen Abfragestruktur ein Zeilenziel von 10. Die Kosten der Operatoren, die zum Zeilenziel führen, werden geändert, um abzuschätzen, wie viele Zeilen sie produzieren müssen, um das Zeilenziel zu erreichen. Diese Berechnung kann komplex werden, daher ist es einfacher, all dies anhand eines vollständig ausgearbeiteten Beispiels und kommentierter Ausführungspläne zu verstehen . Zeilenziele können mehr beeinflussen als die Auswahl des Verknüpfungstyps oder ob Suchvorgänge und Suchvorgänge gegenüber Scans bevorzugt werden. Mehr dazu hier .

Wie immer unterliegt ein auf der Grundlage eines Zeilenziels ausgewählter Ausführungsplan den Argumentationsfähigkeiten des Optimierers und der Qualität der ihm bereitgestellten Informationen. Nicht jeder Plan mit einem Zeilenziel wird in der Praxis die erforderliche Anzahl von Zeilen schneller produzieren, sondern gemäß dem Kalkulationsmodell.

Wenn sich herausstellt, dass ein Zeilenzielplan nicht schneller ist, gibt es normalerweise Möglichkeiten, die Abfrage zu ändern oder dem Optimierer bessere Informationen bereitzustellen, sodass der natürlich ausgewählte Plan am besten ist. Welche Option in Ihrem Fall angemessen ist, hängt natürlich von den Details ab. Das Zeilenziel-Feature ist im Allgemeinen sehr effektiv (obwohl es einen Fehler gibt, auf den Sie achten müssen, wenn Sie es in parallelen Ausführungsplänen verwenden).

Ihre spezielle Anfrage und Ihr Plan sind möglicherweise nicht für eine detaillierte Analyse geeignet (stellen Sie auf jeden Fall einen tatsächlichen Ausführungsplan zur Verfügung, wenn Sie dies wünschen), aber hoffentlich können Sie mit den hier beschriebenen Ideen Fortschritte erzielen.

Paul White sagt GoFundMonica
quelle
12

Wenn Sie TOP verwenden, sieht der Optimierer die Möglichkeit, weniger Arbeit zu erledigen. Wenn Sie nach 10 Zeilen fragen, besteht eine gute Chance, dass nicht der gesamte Satz verbraucht werden muss. So kann der TOP-Operator viel weiter nach rechts geschoben werden. Es fordert so lange Zeilen vom nächsten Operator (rechts von ihm) an, bis es genug empfangen hat.

Sie weisen darauf hin, dass die Abfrage ohne TOP die Daten ganz am Ende sortiert. Wenn die Engine im Voraus wissen könnte, wie viele Zeilen durch den Join erfüllt werden sollen, könnte sie sich für einen ähnlichen Plan entscheiden und das OBEN links positionieren. Da der Aufwand für ein Hash-Match jedoch relativ hoch ist und vermutlich keine Option für einen Merge-Join besteht, zieht das Optimierungsprogramm es möglicherweise vor, das TOP weiter rechts zu filtern.

Wenn Tabelle B abgefragt wird, wird jeweils eine einzelne Zeile abgerufen. Das ist der Grund, warum die Schätzung 1 lautet. Außerdem wird davon ausgegangen, dass diese Zeile in 50% der Fälle nur vorkommt. Es wird also 2n + 1 benötigt, um es zu finden.

Rob Farley
quelle
Es scheint nicht richtig zu sein, dass sich die geschätzte Anzahl der Zeilen abhängig von der Art und Weise ändert, in der die Daten abgerufen werden. Wie es die Daten erhält, sollte die Kardinalität nicht beeinflussen. Eine Änderung in der Art und Weise, wie es abruft, würde sich stattdessen in der Anzahl der Hinrichtungen widerspiegeln, richtig?
David
Die "Geschätzte Anzahl der Zeilen" gilt pro Ausführung. In einer verschachtelten Schleife wird sie mit ziemlicher Wahrscheinlichkeit mehr als einmal ausgeführt.
Rob Farley
Dies wäre dann ein anderes Verhalten als die tatsächliche Anzahl der Zeilen und die (tatsächliche) Anzahl der Ausführungen. Wenn der tatsächliche Plan 16.834 tatsächliche Ausführungen und 15.407 tatsächlich zurückgegebene Zeilen anzeigt, bedeutet dies, dass 16.000 Suchvorgänge ausgeführt wurden, aber nur 15.000 gefunden wurden, die mit dem Prädikat übereinstimmen. Wenn es 15.000 Zeilen pro Ausführung bedeuten würde, wären dies 15.000 * 16.000 = 240 Millionen Zeilen - ungefähr zehnmal größer als die Tabelle ...
David,
Ich bin mir auch nicht sicher, ob ich der letzten Aussage deiner Antwort folge. Wenn Sie sagen, 2n + 1 sucht "es" zu finden, was meinen Sie mit "es"? Sicher nicht eine einzige Reihe? Meinen Sie damit, dass das Optimierungsprogramm davon ausgeht, dass für eine bestimmte Zeile in A eine 50-prozentige Wahrscheinlichkeit besteht, dass sie mit B übereinstimmt, und daher 2003-Zeilen von A "ausprobieren" muss, um 1001 Übereinstimmungen von B zu erhalten? Ist dieses Verhalten irgendwo von Microsoft dokumentiert? Und was hat das mit der TOPKlausel zu tun ? Vielen Dank für Ihre Antwort (en) / Geduld.
David
Ja, die geschätzten Zeilen gelten pro Ausführung. Tatsächliche Zeilen sind total. Obwohl es kein Problem gibt, wenn ein Operator mehr Zeilen als in der Tabelle zurückgibt, ist es sehr einfach zu demonstrieren, dass Operatoren dieselbe Zeile mehrmals zurückgeben.
Rob Farley