Database
 sql >> Datenbank >  >> RDS >> Database

Festlegen und Identifizieren von Zeilenzielen in Ausführungsplänen

Einführung

Die SQL Server-Produktdokumentation ist ein bisschen schwachsinnig in Bezug auf das Thema Zeilenziele . Die wichtigsten offiziellen Referenzen sind in:

  • Hinweise (Transact-SQL) – Abfrage (FAST und DISABLE_OPTIMIZER_ROWGOAL Hinweise)
  • DBCC TRACEON – Trace-Flags (Transact-SQL) (Trace-Flag 4138)
  • Die Ausführung einer Abfrage kann lange dauern, wenn der Abfrageoptimierer den Top-Operator verwendet (KB 2667211)

Wenn Leute nach mehr Informationen fragen, als dort enthalten sind, verweise ich sie normalerweise auf einen oder mehrere der folgenden Punkte:

  • Zeilenziele in Aktion vom SQL Server-Abfrageoptimierungsteam
  • Zeilenziele überarbeitet – SCHNELLE Hinweisanleitung auch vom SQL Server Query Optimization Team
  • Row Goals Gone Rogue von Bart Duncan
  • Inside the Optimizer:Row Goals In Depth von mir
  • Der SSIS-Tuning-Tipp, den jeder vermisst, von Rob Farley

Um es kurz zusammenzufassen:Die Zeilenzielfunktion ermöglicht es dem Optimierer, einen Ausführungsplan (oder Teil(e) eines Ausführungsplans) mit dem Ziel zu generieren, eine bestimmte Anzahl von Zeilen schnell zurückzugeben. Dies steht im Gegensatz zum normalen Verhalten (ohne Zeilenziel), das darauf abzielt, einen Plan zu finden, der für die vollständige potenzielle Ergebnismenge optimiert ist.

Eine Zeilenzielstrategie bedeutet im Allgemeinen, nicht blockierende Navigationsoperationen (z. B. Verknüpfungen mit verschachtelten Schleifen, Indexsuchen und Suchen) gegenüber blockierenden, satzbasierten Operationen wie Sortieren und Hashing zu bevorzugen. Dies kann immer dann nützlich sein, wenn der Client von einem schnellen Start und einem stetigen Strom von Zeilen profitieren kann (mit möglicherweise einer längeren Gesamtausführungszeit – siehe Beitrag von Rob Farley oben). Es gibt auch die offensichtlicheren und traditionelleren Verwendungen, z. beim Präsentieren der Ergebnisse Seite für Seite.

Natürlich ist ein Reihenzielplan mit einem gewissen Risiko verbunden. Wenn alles im Großen und Ganzen wie vom Optimierer erwartet abläuft (angesichts der verfügbaren Informationen und der getroffenen Modellannahmen), beginnt der Ausführungsplan schneller und effizienter mit dem Streamen der angeforderten Anzahl von Zeilen, als dies ohne das Zeilenziel der Fall gewesen wäre.

Wenn die Row-Goal-Strategie schief geht, kann dies leider zu einem Performance-Desaster führen (siehe Beitrag von Bart Duncan). Dies kann beispielsweise passieren, wenn der Optimierer unvollständige Informationen hat, auf eine ungünstige Datenverteilung stößt oder eine unsichere Annahme trifft. In jedem Fall liegt die Ursache für die schlechte Performance fast immer darin, dass zur Ausführungszeit viel mehr Zeilen verarbeitet werden müssen, als der Optimierer erwartet hat.

Es kann sehr nützlich sein, Ausführungsplanbereiche zu identifizieren, die von einem Zeilenziel betroffen sind, weil es uns hilft zu verstehen, warum der Optimierer hat die Entscheidungen getroffen, die er getroffen hat. Dies ist besonders wichtig, wenn die Zeilenziellogik zu einem nachteiligen Ergebnis führt. Ohne die Rolle des Zeilenziels zu verstehen, könnte es so aussehen, als hätte der Optimierer einfach die Anzahl der Zeilen unterschätzt, was dazu führt, dass die Leute an den falschen Stellen (z. B. Statistiken) nach einer Grundursache suchen.

Zeilenziele festlegen

Es ist viel einfacher, nach Zeilenzieleffekten zu suchen, wenn man weiß, welche Dinge dazu führen können, dass ein Zeilenziel überhaupt erst festgelegt wird. Die offizielle Dokumentation spricht oft davon, dass Zeilenziele mit den Schlüsselwörtern TOP verknüpft sind , FAST , IN , und EXISTS . Dies kann beim Leser zu einem unvollständigen oder irreführenden Verständnis führen, daher lohnt es sich, sich einen Moment Zeit zu nehmen, um einige Aspekte zu klären.

Ich möchte gleich vorweg betonen, dass bestimmte T-SQL-Schlüsselwörter verwendet werden in einer Abfrage garantiert nicht, dass ein Zeilenziel gesetzt wird . Die offizielle Dokumentation erwähnt bestimmte Schlüsselwörter, um Menschen dabei zu helfen, allgemeine Szenarien zu identifizieren, in denen Zeilenziele möglicherweise sind eingeführt werden, ohne in zu viele technische Details einzusteigen.

Ein zweiter allgemeiner Punkt, den Sie beachten sollten, ist, dass ein Zeilenziel nur festgelegt wird, wenn das Ziel unter der regulären Schätzung liegen würde . Schließlich macht es wenig Sinn, ein auf 100 Zeilen optimiertes Planfragment zu generieren, wenn das Ganze ohnehin nur 50 Zeilen ergeben soll. Um es besonders deutlich zu machen, dieser Punkt gilt immer für alle Möglichkeiten, wie ein Reihenziel festgelegt werden kann. Wenn Sie ein Zeilenziel erwarten, aber keines sehen, ist dies eine wahrscheinliche Ursache.

Beachten Sie abschließend für die Präambel, dass Zeilenziele eine kostenbasierte Optimierungssache sind; Ein Zeilenziel wirkt sich auf die Auswahl des Optimierers aus. Wenn also keine Auswahl getroffen werden muss (d. h. ein trivialer Plan), gibt es keinen Zeilenzieleffekt.

Schauen wir uns nun die Dinge an, die ein Zeilenziel setzen können:

SCHNELL und TOP

Mit FAST Der Abfragehinweis ist eine zuverlässige Möglichkeit, ein Zeilenziel am Stamm festzulegen des Ausführungsplans (vorbehaltlich der oben genannten allgemeinen Ausnahmen). A SET ROWCOUNT n -Anweisung legt auch ein ähnliches Zeilenziel auf oberster Ebene fest (wenn n ist natürlich nicht Null) für die Aussagen, auf die es sich bezieht.

Schreiben eines TOP -Klausel in einer Abfrage führt auch sehr oft zu einem Zeilenziel. Solange der fertige Ausführungsplan einen physischen Top-Operator enthält, ist es wahrscheinlich, dass zumindest ein Teil des Plans unterhalb des Top-Operators von einem Zeilenziel betroffen war (auch hier gelten die allgemeinen Geschäftsbedingungen).

Beachten Sie, dass Top-Operatoren vom Abfrageoptimierer eingeführt werden (ohne einen durch die Abfrage angegebenen TOP -Klausel) kann auch ein Zeilenziel festlegen. Dies ist wichtig, da dies auf verschiedene Weise geschehen kann, beispielsweise beim Filtern nach einer einfachen Zeilennummer, wie in der folgenden AdventureWorks-Abfrage gezeigt:

SELECT
    THN.RowNum,
    THN.TransactionID 
FROM 
(
    SELECT 
        TH.TransactionID, 
        RowNum = 
            ROW_NUMBER() OVER (
                ORDER BY TH.TransactionID ASC)
    FROM Production.TransactionHistory AS TH
    WHERE
        TH.ProductID = 400
) AS THN
WHERE
    THN.RowNum >= 10
    AND THN.RowNum < 20
ORDER BY
    THN.RowNum ASC;

Der Ausführungsplan für diese Abfrage enthält einen Top-Operator, der vom Optimierer hinzugefügt wurde (um die Anzahl der verarbeiteten Zeilen auf 20 zu begrenzen):