Datenbanken

Server-seitiges Paging mit SQL-Server 2005

Einige ASP.NET-Controls besitzen die Möglichkeit zum seitenweisen Anzeigen der übergebenen Daten (Paging), was auf den ersten Blick sehr sinnvoll ist, um dem Benutzer nicht endlos scrollen lassen zu müssen. Ein Klick auf "nächste Seite" und die nächsten 20 Treffer werden angezeigt. Auf den ersten Blick eine schicke Sache, auf den zweiten aber nicht besonders effizient, denn die gesamten Daten, werden von der ASP.NET.Applikation im Speicher gehalten!

Die bessere Alternative ist ja wohl, sich immer nur die Datenmenge vom Datenbank-Server zu holen, die in dem Moment gebraucht wird, also SQL-Server-Paging zu implementieren.

Bis einschließlich SQL-Server 2000 war ein effizientes serverseitiges Paging mittels T-SQL nicht immer ein Vergnügen. Entweder man pumpte die Daten über eine Stored-Procedure in temporäre Tabellen und ließ sich den Teil der Daten zurückgeben den man gerade brauchte oder man erzeugte dynamisches SQL, was auf die Dauer nur sehr schlecht wartbar war.

Mit der Veröffentlichung der 2005'er-Version des SQL-Servers hielt ein Feature Einzug, daß sich wunderbar für Paging nutzen lässt: ROW_NUMBER.

Kurz etwas zum Feature selbst, auf das Entwickler lange gewartet haben:

Mittels ROW_NUMBER ist man in der Lage dem Resultset einer beliebigen T-SQL-Abfrage Zeilennummer zu verleihen. Zum Beispiel:

SELECT
	ROW_NUMBER() OVER(ORDER BY ModifiedDate DESC) AS 'RowNr',
	FirstName,
	LastName
FROM AdventureWorks.Person.Contact
WHERE EmailPromotion = 2

RowNr   FirstName      LastName
------  -------------  --------------
1       Humberto       Acevedo
2       Gustavo        Achong
3       Kate           Xie
4       Bianca         Hu
5       Christina      Morris
6       Rebecca        Nicholls
...

Über das Argument partition_by_clause kann man sogar Zeilennummern innerhalb einer Gruppe von Datensätzen erzeugen, aber das nur am Rande.

Mit dieser Zeilennummer hat man nun das Werkzeug in der Hand, um über eine Stored-Procedure sehr effektiv ein server-seitiges Paging zu implementieren:

CREATE PROCEDURE procContactsForPromotion
	@Page INT,
	@PageSize INT
AS
BEGIN
	SET NOCOUNT ON;

	WITH rsContacts AS
	(
		SELECT
			ROW_NUMBER() OVER(ORDER BY ModifiedDate DESC) AS 'RowNr',
			FirstName,
			LastName
		FROM AdventureWorks.Person.Contact
		WHERE EmailPromotion = 2
	)

	SELECT *
	FROM rsContacts
	WHERE RowNr BETWEEN (@Page - 1) * @PageSize + 1
		AND @Page * @PageSize
END

Einfacher und performanter gehts nicht. Folgender Aufruf gibt für dieses Beispiel die Datensätze 31 bis 40 aus:

EXEC procContactsForPromotion @Page = 4, @PageSize = 10
kick it on dotnet-kicks.de AddThis Trackback-Url...

2 Kommentare bislang...

  • @Robert
    Ich hab mir auch schon überlegt, ob das geht, aber ich bin zu dem Schluss gekommen, dass man in einem solchen Fall auf dynamisches SQL zurückgreifen muss bzw. CASE-Strukturen verwenden muss.
    2
    Kristof : Montag, 26. Januar 2009 09:37
  • Klappt wunderbar. ich möchte aber nun das Sortierfeld auch noch paramerisieren:
    Mit OVER(ORDER BY @Sort) AS 'RowNr' klappts aber nicht???
    1
    Robert Marti : Freitag, 23. Januar 2009 12:05

Dein Kommentar hierzu...


Kommentar-Feed für diesen Beitrag
Gravatare werden unterstützt .:. eMail-Adressen werden nicht veröffentlicht
 

RSS-Feed

Die URL des Standard-Newsfeed von zerbit.de lautet:

http://www.zerbit.de/rssfeed.aspx

Login


 

 

Statistik



kürzlich kommentiert

Artikel 263

  • Datum: 03.06.2008
    Kategorie: Datenbanken
    Zugriffe: 3.645
    Kommentare: 2
    Trackbacks: 0

Letzte Beiträge

Kategorien

Buttons & More

Blog-Roll

Banner Piraten-Partei