Warum mehr (und unterschiedlich viele) logische Lesevorgänge mit Vorauslesen (Prefetch)?

8

Nach dem Erstellen der tpch-Datenbank in meinem SQL Server habe ich die folgende Abfrage versucht:

    set statistics io on
    DBCC DROPCLEANBUFFERS;        
    select top 100 * from dbo.lineitem order by l_partkey;

Das Tabellenzeilenelement hat einen nicht gruppierten Index für l_partkey. Ich habe die obigen Abfragen mehrmals ausgegeben und festgestellt, dass die logischen Lesevorgänge jedes Mal variieren:

    Table 'lineitem'. Scan count 1, logical reads 1019, physical reads 4, read-ahead reads 1760, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'lineitem'. Scan count 1, logical reads 1007, physical reads 4, read-ahead reads 1720, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'lineitem'. Scan count 1, logical reads 1030, physical reads 4, read-ahead reads 1792, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Aus dem Beitrag hier: Die Anzahl der logischen Lesevorgänge variiert . Ich weiß, dass dies durch das Vorleseverhalten verursacht werden kann.

ABER genau, warum Vorauslesen zu logischeren Lesevorgängen führen kann? Wie ändert sich das SQL Server-Verhalten? Wie SQL Server kann mehr Indexseite lesen, da es sowieso im Cache ist?

Wie auch immer, ich habe das Vorauslesen deaktiviert und die obige Abfrage erneut ausgegeben. Jetzt werden jedes Mal die gleichen logischen Lesevorgänge gemeldet. ABER die logischen Lesevorgänge sind viel kleiner !!

    Table 'lineitem'. Scan count 1, logical reads 404, physical reads 160, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Meine Frage ist also, warum die Vorauslesefunktion viel mehr und verschiedene logische Lesevorgänge verursachen kann.

Aus Neugier habe ich eine andere Abfrage ohne "order by" versucht:

    select top 100 * from dbo.lineitem

Hier ist das Ergebnis ohne vorher zu lesen:

    Table 'lineitem'. Scan count 1, logical reads 5, physical reads 3, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Hier ist das Ergebnis mit Vorauslesen:

    Table 'lineitem'. Scan count 1, logical reads 15, physical reads 2, read-ahead reads 3416, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Der mit Vorauslesen hat noch mehr logische Lesevorgänge. Warum also?

user3610199
quelle

Antworten:

9

Der Abfrageplan für das ORDER BY l_partkeyBeispiel liest mit ziemlicher Sicherheit den nicht gruppierten Index in der Reihenfolge (mit Vorauslesen), gefolgt von einer Schlüsselsuche, um die nicht abgedeckten Spalten abzurufen.

Der Operator "Verschachtelte Schleifen verbinden" über der Suche verwendet wahrscheinlich zusätzliches Prefetching ( WithOrderedPrefetch) für die Suche. Weitere Informationen finden Sie in dem folgenden Artikel, den ich geschrieben habe:

Wie ich in der Antwort auf die verknüpften Fragen und Antworten erwähnt habe, hängt die Anzahl der Vorauslesevorgänge vom Timing und den Eigenschaften des Speichersubsystems ab. Die gleichen Überlegungen gelten für das Lookup-Prefetching beim Join für verschachtelte Schleifen.

Beachten Sie, dass SQL Server Vorauslesevorgänge für Seiten ausgibt, die möglicherweise vom Index-Scan benötigt werden. Dies ist jedoch nicht durch die TOPSpezifikation in der Abfrage beschränkt. Das TOPist ein Abfrageprozessorelement, während das Vorauslesen von der Storage Engine gesteuert wird.

Die Aktivitäten sind sehr unterschiedlich: Beim Vorauslesen (und Vorabrufen) werden asynchrone E / A für Seiten ausgegeben, die möglicherweise vom Scan (oder der Suche) benötigt werden.

Abhängig von der Reihenfolge, in der E / A tatsächlich abgeschlossen werden und dem Abfrageprozessor (unter anderem) Zeilen zur Verfügung gestellt werden, kann die Anzahl der tatsächlich berührten (logischen Lesevorgänge) oder physischen Lesevorgänge variieren. Beachten Sie insbesondere, dass der verzögerte Vorabruf der Suche auch zu den logischen Lesevorgängen beiträgt, wenn überprüft wird, ob sich eine für die Suche benötigte Seite bereits im Speicher befindet oder nicht.

Es kommt also auf das detaillierte Timing überlappender Operationen an: Der Abfrageprozessor beginnt, die Pipeline für die Abfrageausführung herunterzufahren, sobald die erforderliche Anzahl von Zeilen (100) im obersten Iterator angezeigt wurde. Wie viele asynchrone E / A (Vorauslesen oder Vorabrufen) zu diesem Zeitpunkt ausgegeben oder abgeschlossen wurden, ist im Wesentlichen nicht deterministisch.

Sie können das Prefetching für verschachtelte Schleifen mit dem Ablaufverfolgungsflag 8744 deaktivieren , um dies weiter zu untersuchen. Dadurch wird die WithOrderedPrefetchEigenschaft aus dem Nested Loops Join entfernt. Normalerweise verwende ich OPTION (QUERYTRACEON 8744)die Abfrage selbst. In jedem Fall müssen Sie sicherstellen, dass Sie einen zwischengespeicherten Plan mit dem Prefetch nicht wiederverwenden. Leeren Sie den Plan-Cache jedes Mal oder erzwingen Sie eine Neukompilierung der Abfrage mit OPTION (RECOMPILE).

Logische Lesevorgänge sind ein einfaches Maß für die Anzahl der Cache-Seiten, die im Auftrag der Abfrage berührt wurden. Wenn das Vorauslesen (und / oder Vorabrufen) aktiviert ist, können mehr (und andere!) Index- und Datenseiten berührt werden, um das Vorlesen oder als Teil der Vorabrufaktivität auszugeben.

Paul White 9
quelle