Sollte ich LINQs Skip()
und Take()
Methoden für das Paging verwenden oder mein eigenes Paging mit einer SQL-Abfrage implementieren?
Welches ist am effizientesten? Warum sollte ich einen über den anderen wählen?
Ich verwende SQL Server 2008, ASP.NET MVC und LINQ.
sql
sql-server
asp.net-mvc
linq-to-sql
pagination
Steinherz
quelle
quelle
Antworten:
Wenn Sie versuchen, eine kurze Antwort auf Ihre Zweifel zu geben, verwendet
skip(n).take(m)
Ihre Abfrage dieSelect ROW_NUMBER() Over ...
Anweisung , wenn Sie die Methoden unter linq ausführen (mit SQL 2005/2008 als Datenbankserver) , wobei es sich um ein direktes Paging in der SQL-Engine handelt.Als Beispiel habe ich eine DB-Tabelle namens
mtcity
und habe die folgende Abfrage geschrieben (arbeite auch mit linq to entity):Die resultierende Abfrage lautet:
Das ist ein Fensterdatenzugriff (ziemlich cool, übrigens, weil er von Anfang an Daten zurückgibt und auf die Tabelle zugreift, solange die Bedingungen erfüllt sind). Dies wird sehr ähnlich sein zu:
Mit der Ausnahme, dass diese zweite Abfrage schneller als das linq-Ergebnis ausgeführt wird, da ausschließlich der Index zum Erstellen des Datenzugriffsfensters verwendet wird. Dies bedeutet, wenn Sie eine Filterung benötigen, sollte die Filterung in der Entitätsliste (wo die Zeile erstellt wird) sein (oder müssen) und einige Indizes sollten ebenfalls erstellt werden, um die gute Leistung aufrechtzuerhalten.
Was ist besser?
Wenn Ihre Logik einen ziemlich soliden Workflow enthält, ist die Implementierung der richtigen SQL-Methode kompliziert. In diesem Fall ist LINQ die Lösung.
Wenn Sie diesen Teil der Logik direkt in SQL (in einer gespeicherten Prozedur) senken können, ist dies sogar noch besser, da Sie die zweite Abfrage, die ich Ihnen gezeigt habe (mithilfe von Indizes), implementieren und SQL erlauben können, den Ausführungsplan des zu generieren und zu speichern Abfrage (Verbesserung der Leistung).
quelle
Versuchen Sie es mit
um die Zeilen von 501 bis 600 auf dem SQL Server abzurufen, ohne sie in den Speicher zu laden. Beachten Sie, dass diese Syntax mit verfügbar geworden ist , SQL Server 2012 nur
quelle
Während LINQ-to-SQL eine
OFFSET
Klausel generiert (möglicherweiseROW_NUMBER() OVER()
wie von anderen erwähnt emuliert ), gibt es eine völlig andere, viel schnellere Möglichkeit, Paging in SQL durchzuführen. Dies wird oft als "Suchmethode" bezeichnet, wie in diesem Blog-Beitrag hier beschrieben .Die Werte
@previousScore
und@previousPlayerId
sind die jeweiligen Werte des letzten Datensatzes von der vorherigen Seite. Auf diese Weise können Sie die "nächste" Seite abrufen. Wenn dieORDER BY
Richtung istASC
, verwenden Sie>
stattdessen einfach .Mit der obigen Methode können Sie nicht sofort zu Seite 4 springen, ohne zuvor die vorherigen 40 Datensätze abgerufen zu haben. Aber oft will man sowieso nicht so weit springen. Stattdessen erhalten Sie eine viel schnellere Abfrage, mit der Daten je nach Indizierung möglicherweise in konstanter Zeit abgerufen werden können. Außerdem bleiben Ihre Seiten "stabil", unabhängig davon, ob sich die zugrunde liegenden Daten ändern (z. B. auf Seite 1, während Sie sich auf Seite 4 befinden).
Dies ist der beste Weg, um Paging zu implementieren, wenn beispielsweise mehr Daten in Webanwendungen verzögert geladen werden.
Beachten Sie, dass die " Suchmethode " auch als Keyset-Paging bezeichnet wird .
quelle
LinqToSql konvertiert automatisch einen .Skip (N1) .Take (N2) für Sie in die TSQL-Syntax. Tatsächlich erstellt jede "Abfrage", die Sie in Linq ausführen, nur eine SQL-Abfrage für Sie im Hintergrund. Um dies zu testen, führen Sie einfach SQL Profiler aus, während Ihre Anwendung ausgeführt wird.
Die Skip / Take-Methode hat für mich und andere nach dem, was ich gelesen habe, sehr gut funktioniert.
Welche Art von Self-Paging-Abfrage haben Sie aus Neugier, die Ihrer Meinung nach effizienter ist als das Überspringen / Nehmen von Linq?
quelle
Wir verwenden einen in Dynamic SQL eingeschlossenen CTE (da unsere Anwendung eine dynamische Sortierung der Datenserverseite erfordert) innerhalb einer gespeicherten Prozedur. Ich kann ein einfaches Beispiel liefern, wenn Sie möchten.
Ich hatte keine Gelegenheit, mir das von LINQ erzeugte T / SQL anzusehen. Kann jemand eine Probe posten?
Wir verwenden weder LINQ noch direkten Zugriff auf die Tabellen, da wir die zusätzliche Sicherheitsebene benötigen (vorausgesetzt, das dynamische SQL unterbricht dies etwas).
So etwas sollte den Trick machen. Sie können parametrisierte Werte für Parameter usw. hinzufügen.
quelle
sp_executesql
Sie die Möglichkeit, Parameter auf sichere Weise zu übergeben, zEXECUTE sp_executesql 'WITH myCTE AS ... WHERE Col4=@p1) ...', '@p1 nvarchar(max)', @ValueForCol4
. Sicher bedeutet in diesem Zusammenhang, dass es robust gegen SQL-Injection ist - Sie können jeden möglichen Wert innerhalb der Variablen übergeben@ValueForCol4
- sogar'--'
, und die Abfrage funktioniert weiterhin!SELECT ROW_NUMBER() OVER (ORDER BY CASE WHEN @CampoId = 1 THEN Id WHEN @CampoId = 2 THEN field2 END)
ROW_NUMBER() OVER()
Offset - Emulation. Siehe auch: 4guysfromrolla.com/webtech/042606-1.shtmlIn SQL Server 2008:
In t0 sind alle Datensätze. In t1 sind nur diejenigen, die dieser Seite entsprechen
quelle
Der Ansatz, den ich gebe, ist die schnellste Paginierung, die SQL Server erreichen kann. Ich habe dies an 5 Millionen Datensätzen getestet. Dieser Ansatz ist weitaus besser als der von SQL Server bereitgestellte "OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY".
quelle
Sie können die Leistung weiter verbessern, überprüfen Sie dies
Wenn Sie das from auf diese Weise verwenden, erhalten Sie ein besseres Ergebnis:
Grund: Weil Sie die where-Klasse in der CityEntities-Tabelle verwenden, die viele Datensätze eliminiert, bevor Sie sich der MtCity anschließen. 100% sicher, dass dies die Leistung um ein Vielfaches erhöht ...
Auf jeden Fall ist die Antwort von rodrigoelp wirklich hilfreich.
Vielen Dank
quelle
@p0
und insbesondere@p1
kommt ausSie können Paging auf diese einfache Weise implementieren, indem Sie PageIndex übergeben
quelle
Im Jahr 2008 können wir Skip () nicht verwenden. Take ()
Der Weg ist:
quelle