Wie funktioniert Paging mit ROW_NUMBER in SQL Server?

13

Ich habe einen EmployeeTisch mit einer Million Datensätzen. Ich verfolge SQL zum Paging von Daten in einer Webanwendung. Es funktioniert gut. Was ich jedoch als Problem sehe, ist, dass die abgeleitete Tabelle tblEmployeealle Datensätze in der EmployeeTabelle auswählt (um die MyRowNumberWerte zu erstellen ).

Ich denke, dies bewirkt die Auswahl aller Datensätze in der EmployeeTabelle.

Funktioniert es wirklich so? Oder ist SQL Server so optimiert, dass nur die 5 Datensätze aus der Originaltabelle ausgewählt Employeewerden?

DECLARE @Index INT;
DECLARE @PageSize INT;

SET @Index = 3;
SET @PageSize = 5;

SELECT *  FROM
  (SELECT  ROW_NUMBER() OVER (ORDER BY EmpID asc) as MyRowNumber,*
  FROM Employee) tblEmployee
WHERE MyRowNumber BETWEEN ( ((@Index - 1) * @PageSize )+ 1) AND @Index*@PageSize 
LCJ
quelle

Antworten:

17

Eine Alternative zum Testen könnte sein:

;WITH x AS (SELECT EmpID, k = ROW_NUMBER() OVER (ORDER BY EmpID) FROM dbo.Emp)
SELECT e.columns
FROM x INNER JOIN dbo.Emp AS e
ON x.EmpID = e.EmpID
WHERE x.k BETWEEN (((@Index - 1) * @PageSize) + 1) AND @Index * @PageSize
ORDER BY ...;

Ja, Sie haben zweimal auf den Tisch geschlagen, aber im CTE, in dem Sie den gesamten Tisch scannen, greifen Sie nur auf den Schlüssel zu, nicht auf ALLE Daten. Aber du solltest dir diesen Artikel wirklich ansehen:

http://www.sqlservercentral.com/articles/T-SQL/66030/

Und die anschließende Diskussion:

http://www.sqlservercentral.com/Forums/Topic672980-329-1.aspx

In SQL Server 2012 können Sie natürlich die neue OFFSET/ FETCH NEXT-Syntax verwenden:

;WITH x AS 
(
  SELECT EmpID FROM dbo.Emp
    ORDER BY EmpID
    OFFSET  @PageSize * (@Index - 1) ROWS
    FETCH NEXT @PageSize ROWS ONLY
)
SELECT e.columns
FROM x INNER JOIN dbo.Emp AS e
ON x.EmpID = e.EmpID
ORDER BY ...; 
Aaron Bertrand
quelle
Es sollte jedoch beachtet werden, dass OFFSET / FETCH NEXT keine Leistungsvorteile gegenüber der CTE-Methode bieten
Akash
2
@Akash hast du das gründlich getestet? Ich habe einige Planunterschiede beobachtet, aber nichts spezielles über die Leistung erwähnt, weil ich keine umfangreichen Tests durchgeführt habe. Selbst wenn die Leistung gleich ist, ist die Syntax etwas weniger umständlich. Ich habe hier darüber gebloggt
Aaron Bertrand
1
Ah, du hast recht, es gibt einen Leistungsunterschied. Ich hatte folgendes gelesen: blogs.technet.com/b/dataplatforminsider/archive/2011/11/01/… wo er keinen Unterschied erwähnt, sondern nur channel9.msdn.com/posts/SQL11UPD03-REC-02 wo er es zeigt viel Unterschied .. (obwohl in der Audio-Unter Betonung der Leistungsunterschied)
Akash
2

Obwohl Sie den Mechanismus dahinter möglicherweise nicht kennen, können Sie dies selbst testen, indem Sie die Leistung Ihrer Abfrage mit Folgendem vergleichen: Wählen Sie * aus Mitarbeiter.

Die neueren Versionen von SQL Server können zwar recht gut optimiert werden, dies kann jedoch von mehreren Faktoren abhängen.

Die Leistung Ihrer ROW_NUMBER-Funktion wird durch die Order By-Klausel bestimmt. In Ihrem Beispiel würden die meisten davon ausgehen, dass EmpID der Primärschlüssel ist.

Es gibt einige where- Klauseln, die so komplex und / oder schlecht codiert oder indexiert sind, dass Sie möglicherweise besser daran sind, nur den gesamten Datensatz zurückzugeben (dies ist selten und kann behoben werden). Die Verwendung von BETWEEN hat Probleme.

Bevor Sie davon ausgehen, dass es besser ist, alle Zeilen an Ihre Anwendung zurückzugeben und es herauszufinden, sollten Sie Ihre Abfrage optimieren. Überprüfen Sie die Schätzungen. Fragen Sie den Query Analyzer. Testen Sie einige Alternativen.

JeffO
quelle
2

Ich weiß, dass die Frage row_number () betrifft, aber ich möchte eine neue Funktion von SQL Server 2012 hinzufügen. In SQL Server 2012 wird die neue Funktion OFFSET Fetch als nächste eingeführt und sie ist sehr schnell als row_number (). Ich habe es benutzt und es gibt mir ein gutes Ergebnis, hoffe ihr füllt auch die gleiche Erfahrung.

Ich fand ein Beispiel auf http://blogfornet.com/2013/06/sql-server-2012-offset-use/

das ist nützlich. Hoffe, es wird Ihnen auch bei der Implementierung neuer Funktionen helfen ....

Sam Raj
quelle
-2

Ich denke nicht, dass es auswertet, um alle Zeilen in der ursprünglichen Tabelle zurückzugeben. SQL Server optimiert. Andernfalls dauert es sehr lange, bis eine Million Einträge ausgewählt sind. Ich verwende dies derzeit und es ist viel schneller als die Auswahl aller Zeilen. Also, bekommt sicher nicht alle Zeilen. Es ist jedoch langsamer als nur das Abrufen der ersten fünf Zeilen, wahrscheinlich aufgrund des Zeitaufwands bei der Bestellung

user3688672
quelle
-2
DECLARE @PageIndex int;
DECLARE @PageSize int;
SET @PageIndex = 4;
SET @PageSize = 5;
;With ranked AS   --- Or you can make it a view
(
   SELECT ROW_NUMBER() OVER(ORDER BY IdentityId) AS RowNum,  *
   FROM logeventnew
)
SELECT *   --Your fields here
FROM Ranked
WHERE RowNum BETWEEN ((@PageIndex - 1) * @PageSize + 1)
    AND (@PageIndex * @PageSize)
ORDER BY IdentityId
Agnel Amodia
quelle
4
Könnten Sie Ihre Antwort erweitern? Die Frage war, wie das Paging in SQL Server intern funktioniert - dh was macht das Datenbankmodul, um die Anforderung zu erfüllen. Leider geht Ihre Antwort derzeit nicht auf das eigentliche Problem ein.
Mr. Brownstone