Paginierung in SQL Server


17

Ich habe eine sehr große Datenbank, ungefähr 100 GB. Ich führe eine Abfrage aus:

select * from <table_name>;

und ich möchte nur die 100. bis 200. Reihe zeigen.

Ich möchte verstehen, wie dies intern geschieht. Ruft die Datenbank alle Datensätze von der Festplatte in den Speicher ab und sendet die 100. bis 400. Zeile an den abfragenden Client zurück? Oder gibt es einen Mechanismus, mit dem nur die Datensätze (100.-200.) Aus der Datenbank abgerufen werden - mithilfe von Indizierungsmechanismen wie B-Bäumen usw.?

Ich fand, dass dies mit dem Paginierungskonzept zusammenhängt, konnte aber nicht genau herausfinden, wie es intern auf Datenbankebene geschieht.

Antworten:


37

In der Abfrage, die Sie gepostet haben:

select * from <table_name>;

Es gibt keine 100. bis 200. Zeile, da Sie kein ORDER BY angeben. Die Bestellung kann nur garantiert werden, wenn Sie ORDER BY aus einer Reihe interessanter Gründe angeben, aber das ist hier nicht der eigentliche Punkt.

Um dies zu veranschaulichen, verwenden wir eine Tabelle. Ich verwende die Users-Tabelle aus dem Stack Overflow-Daten-Dump und führe die folgende Abfrage aus:

SELECT * FROM dbo.Users ORDER BY DisplayName;

Standardmäßig enthält das Feld Anzeigename keinen Index, sodass SQL Server die gesamte Tabelle scannen und nach Anzeigename sortieren muss. Hier ist der Ausführungsplan :

Clustered Index Scan mit einer Sortierung

Es ist nicht schön - das ist eine Menge Arbeit mit geschätzten Teilbaumkosten von ungefähr 30.000. (Sie können es sehen, indem Sie den Mauszeiger über den Auswahloperator bei PasteThePlan bewegen.) Was passiert also, wenn wir nur Zeilen 100-200 wollen? Wir können diese Syntax in SQL Server 2012+ verwenden:

SELECT * FROM dbo.Users ORDER BY DisplayName OFFSET 100 ROWS FETCH NEXT 100 ROWS ONLY;

Der Ausführungsplan dazu ist auch ziemlich hässlich:

Clustered Index Scan mit einer Sortierung und einem Top

SQL Server durchsucht weiterhin die gesamte Tabelle, um die sortierte Liste zu erstellen, damit Sie 100 bis 200 Zeilen erhalten, und die Kosten belaufen sich weiterhin auf rund 30.000. Schlimmer noch, diese ganze Liste wird jedes Mal neu erstellt, wenn Ihre Abfrage ausgeführt wird (schließlich hat möglicherweise jemand seinen Anzeigenamen geändert.)

Damit es schneller geht, können wir einen nicht gruppierten Index für DisplayName erstellen, der eine Kopie unserer Tabelle ist und nach diesem bestimmten Feld sortiert ist:

CREATE INDEX IX_DisplayName ON dbo.Users(DisplayName);

Mit diesem Index führt der Ausführungsplan unserer Abfrage nun eine Indexsuche durch:

Indexsuche und Schlüsselsuche

Die Abfrage wird sofort beendet und hat einen geschätzten Teilbaumaufwand von nur 0,66 (im Gegensatz zu 30.000).

Wenn Sie die Daten so organisieren, dass die von Ihnen häufig ausgeführten Abfragen unterstützt werden, kann SQL Server Verknüpfungen verwenden, um Ihre Abfragen zu beschleunigen. Wenn Sie dagegen nur Heaps oder Clustered-Indizes haben, sind Sie fertig.


"Standardmäßig enthält das Feld" Anzeigename "keinen Index, sodass SQL Server die gesamte Tabelle durchsuchen und nach Anzeigename sortieren muss." Entschuldigen Sie, wenn dies eine sehr grundlegende Frage ist - für den Fall, dass ich aus Ihrer Antwort "Wann Sie" zitiert habe sagte "Gesamte Tabelle scannen", bedeutet das, dass alle Daten in den Speicher gebracht und sortiert werden (was nicht wie der richtige Weg aussieht)?
AV94

Aus Ihrer Antwort geht hervor, dass, wenn das Feld indiziert ist, Abfragen wie "100. bis 200. Zeile" sehr effizient sind, da SQL zum Index (B-Baum usw.) aufruft und direkt zu diesem Punkt (100. Zeile) übergeht. Könnten Sie mir bitte sagen, ob dies das richtige Verständnis ist?
AV94

@AnilVedala zu deiner ersten Frage - ja, die Daten müssen sortiert werden. Wie sonst könnte eine Datenbank dies mit einer unsortierten Liste erreichen?
Brent Ozar

1
@AnilVedala über Ihre zweite Frage - hier kommt der letzte Ausführungsplan, den ich Ihnen gegeben habe. (Wenn Sie fragen, wie Sie einen Ausführungsplan lesen sollen, lesen Sie das Buch Ausführungspläne von Grant Fritchey.)
Brent Ozar

15

Nur als Ergänzung zu Brents Antwort, wenn ein nicht abdeckender Index verwendet wird, um eine Sortierung zu vermeiden, gibt es ein potenzielles Problem mit späteren Seitenzahlen, das sich aus der folgenden Liste ergibt

SELECT * 
FROM dbo.Users 
ORDER BY DisplayName 
OFFSET 100000 ROWS 
FETCH NEXT 100 ROWS ONLY;

Der Ausführungsplan zeigt, dass die Suche 100.100-mal ausgeführt wurde, obwohl dann alle bis auf 100 Zeilen vom TOP-Operator herausgefiltert wurden.

Bildbeschreibung hier eingeben

Dies kann mithilfe des folgenden Musters verringert werden

WITH T
     AS (SELECT Id,
                DisplayName
         FROM   dbo.Users
         ORDER  BY DisplayName
        OFFSET 100000 ROWS 
        FETCH NEXT 100 ROWS ONLY
        )
SELECT U.*
FROM   dbo.Users U
       JOIN T
         ON U.Id = T.Id
ORDER  BY T.DisplayName 

Dadurch werden alle Zeilen mit Ausnahme der letzten 100 herausgefiltert, bevor die Suchvorgänge ausgeführt werden, was sich bei großen Offsetwerten erheblich auf die Geschwindigkeit auswirken kann.

Bildbeschreibung hier eingeben


3

Es hängt wirklich davon ab, wie Sie die Paginierung in Ihre Abfrage implementieren, wie die Daten beschaffen sind und wie Ihr System konfiguriert ist. Es ist ziemlich sicher zu sagen, dass SQL Server versucht, Ihre Daten mit dem geringstmöglichen Aufwand zurückzugeben. Wenn Sie keine explizite Sortierreihenfolge, Filterung, Gruppierung oder Fensterung haben, kann SQL Server möglicherweise den Abfrageplan so optimieren, dass nur die Seiten von der Festplatte zurückgegeben werden, die die für Ihre Abfrage erforderlichen Daten enthielten - oder sogar direkt von der Pufferpool. Sobald Sie anfangen, die Abfrage so zu ändern, dass sie Sortieren, Gruppieren, Fenstern und Filtern umfasst, wird es kompliziert.

Es ist ein sehr guter Artikel über SQL Performance hier , die in einige Details der verschiedenen Methoden der Paginierung geht und wie sie den Abfrageplan beeinflussen. Ich würde es sehr empfehlen, es zu lesen und dann einige der verschiedenen Methoden auszuprobieren, auf die sie hinweisen, und zu sehen, welcher Abfrageplan auf Ihrem eigenen System ausgewählt wurde.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.