Im Laufe der Jahre ist ein Haufen Entwicklerschweiß in das effiziente Paging von Ergebnismengen geflossen. Es gibt jedoch keine Patentlösung – es hängt von Ihrem Anwendungsfall ab. Ein Teil des Anwendungsfalls besteht darin, Ihre Seite effizient zu erhalten, ein Teil besteht darin, herauszufinden, wie viele Zeilen in einem vollständigen Ergebnissatz enthalten sind. Tut mir leid, wenn ich ein wenig ins Paging abschweife, aber die beiden sind in meinen Augen ziemlich eng miteinander verbunden.
Es gibt viele Strategien, von denen die meisten schlecht sind, wenn Sie irgendein Datenvolumen haben und nicht zum Anwendungsfall passen. Obwohl dies keine vollständige Liste ist, sind im Folgenden einige der Optionen aufgeführt.....
Separate Count(*)
ausführen
- Führen Sie eine separate Abfrage aus, die ein einfaches "select count(*) from MyTable" durchführt
- einfach und leicht für einen kleinen Tisch
- Gut für eine ungefilterte große Tabelle, die entweder schmal ist oder einen kompakten, nicht gruppierten Index hat, den Sie verwenden können
- bricht zusammen, wenn Sie ein kompliziertes
WHERE/JOIN
haben Kriterien, weilWHERE/JOIN
ausgeführt wird zweimal ist teuer. - bricht bei einem breiten Index zusammen, da die Anzahl der Lesevorgänge steigt.
Kombiniere ROW_Number() OVER()
und COUNT(1) OVER(PARTITION By 1)
- Dies wurde von @RBarryYoung vorgeschlagen. Es hat den Vorteil, dass es einfach zu implementieren und sehr flexibel ist.
- Die Kehrseite ist, dass es viele Gründe dafür gibt, dass dies schnell extrem teuer werden kann.
- Zum Beispiel, in einer Datenbank, an der ich gerade arbeite, gibt es eine Media-Tabelle mit etwa 6000 Zeilen. Es ist nicht besonders breit, hat einen ganzzahligen geclusterten PK und einen kompakten eindeutigen Index. Aber ein einfaches
COUNT(*) OVER(PARTITION BY 1) as TotalRows
ergibt ~12.000 Lesevorgänge. Vergleichen Sie das mit einem einfachenSELECT COUNT(*) FROM Media
- 12 mal gelesen. Wowzer.
Temporäre Tabellen / Tabellenvariablen
- Es gibt viele Strategien, die eine Ergebnismenge nehmen und relevante Schlüssel oder Ergebnissegmente in temporäre Tabellen/Tabellenvariablen einfügen.
- Bei kleinen/mittelgroßen Resultsets kann dies hervorragende Ergebnisse liefern.
- Diese Art von Strategie funktioniert auf fast jeder Plattform/Version von SQL.
- Das mehrfache Bearbeiten einer Ergebnismenge (häufig eine Anforderung) ist ebenfalls einfach.
- Die Kehrseite ist, wenn man mit großen Ergebnismengen arbeitet ... das Einfügen von ein paar Millionen Zeilen in eine temporäre Tabelle ist mit Kosten verbunden.
- Um das Problem noch zu verschärfen, kann der Systemdruck auf TempDB in einem hohen Volumen ein ziemlicher Faktor sein, und temporäre Tabellen funktionieren effektiv in TempDB.
Gaußsche Summe / Doppelreihenzahl
- Diese Idee beruht auf Teilmenge von etwas, das der Mathematiker Gauß herausgefunden hat (wie man eine Reihe von Zahlen summiert). Die Teilmenge gibt an, wie man die Zeilenanzahl von jedem Punkt in der Tabelle erhält.
- Aus einer Reihe von Zahlen (
Row_Number()
) ist die Zeilenanzahl für 1 bis N(N + 1) - 1
. Weitere Erklärungen in den Links. - Die Formel sieht so aus, als würde sie nur N ergeben, aber wenn Sie sich an die Formel halten, passieren interessante Dinge:Sie können die Anzahl der Zeilen auf einer Seite in der Mitte der Tabelle ermitteln.
- Das Endergebnis ist, dass Sie
ROW_Number() OVER(Order by ID)
ausführen undROW_Number() OVER(Order by ID DESC)
dann addiere die beiden Zahlen und subtrahiere 1. - Am Beispiel meiner Media-Tabelle sind meine Reads von 12.000 auf etwa 75 gesunken.
- Auf einer größeren Seite haben Sie Daten viele Male wiederholt, aber der Offset bei den Lesevorgängen kann sich lohnen.
- Ich habe dies nicht in zu vielen Szenarien getestet, daher kann es in anderen Szenarien auseinanderfallen.
Oben (@n) / ZEILENZAHL EINSTELLEN
- Dies sind per se keine spezifischen Strategien, sondern Optimierungen, die auf unserem Wissen über den Abfrageoptimierer basieren.
- Die kreative Verwendung von Top(@n) [top kann eine Variable in SQL 2008 sein] oder SET ROWCOUNT kann Ihr Arbeitsset reduzieren ... selbst wenn Sie eine mittlere Seite eines Resultsets ziehen, können Sie das Ergebnis immer noch eingrenzen
- Diese Ideen funktionieren aufgrund des Verhaltens des Abfrageoptimierers ... ein Service Pack/Hotfix kann das Verhalten ändern (obwohl wahrscheinlich nicht).
- In bestimmten Fällen kann SET ROWCOUNT etwas ungenau sein
- Diese Strategie berücksichtigt nicht das Abrufen der vollständigen Zeilenanzahl, sondern macht das Paging nur effizienter
Was soll ein Entwickler also tun?
Lesen Sie, mein guter Mann, lesen Sie. Hier sind einige Artikel, auf die ich mich gestützt habe...
- Eine effizientere Methode zum Blättern durch große Ergebnismengen
- Optimierung von serverseitigem Paging – Teil I
- Optimierung von serverseitigem Paging – Teil II
- Erklärung der Gaußschen Summe
- Ranglistenergebnisse mit Microsoft SQL Server 2005 zurückgeben
- ROW_NUMBER() OVER nicht schnell genug bei großer Ergebnismenge
- Abrufen der ersten N Datensätze aus einer SQL-Abfrage
- Serverseitiges Paging mit SQL Server 2005
- Warum sind logische Lesevorgänge für gefensterte Aggregatfunktionen so hoch?
Hoffe das hilft.