Frage

Viele Anwendungen haben Gitter, die Anzeige von Daten aus einer Datenbank-Tabelle auf einer Seite gleichzeitig.Viele von Ihnen lassen Sie die Benutzer wählen Sie die Anzahl der Datensätze pro Seite Sortieren nach einer Spalte, und vor und zurück navigieren Sie durch die Ergebnisse.

Was ist ein guter Algorithmus zum implementieren dieser Muster, ohne dass die gesamte Tabelle auf den client und dann filtern der Daten auf den client.Wie bringen Sie nur die Datensätze, die Sie anzeigen möchten, um die Benutzer?

Tut LINQ vereinfacht die Lösung?

War es hilfreich?

Lösung

Auf dem MS SQL Server 2005 und höher ROW_NUMBER() scheint zu funktionieren:

T-SQL:Paging mit ROW_NUMBER()

DECLARE @PageNum AS INT;
DECLARE @PageSize AS INT;
SET @PageNum = 2;
SET @PageSize = 10;

WITH OrdersRN AS
(
    SELECT ROW_NUMBER() OVER(ORDER BY OrderDate, OrderID) AS RowNum
          ,OrderID
          ,OrderDate
          ,CustomerID
          ,EmployeeID
      FROM dbo.Orders
)

SELECT * 
  FROM OrdersRN
 WHERE RowNum BETWEEN (@PageNum - 1) * @PageSize + 1 
                  AND @PageNum * @PageSize
 ORDER BY OrderDate
         ,OrderID;

Andere Tipps

Ich würde empfehlen entweder die Verwendung von LINQ, oder versuchen, Sie zu kopieren, was es tut.Ich habe eine app, wo ich den LINQ Nehmen und Überspringen Sie die Methoden zum abrufen von ausgelagerten Daten.Der code sieht ungefähr so aus:

MyDataContext db = new MyDataContext();
var results = db.Products
    .Skip((pageNumber - 1) * pageSize)
    .Take(pageSize);

Mit SQL Server Profiler zeigt, dass LINQ konvertieren diese Abfrage in SQL ähnlich:

SELECT [ProductId], [Name], [Cost], and so on...
FROM (
    SELECT [ProductId], [Name], [Cost], [ROW_NUMBER]
    FROM (
       SELECT ROW_NUMBER() OVER (ORDER BY [Name]) AS [ROW_NUMBER], 
           [ProductId], [Name], [Cost]
       FROM [Products]
    )
    WHERE [ROW_NUMBER] BETWEEN 10 AND 20
)
ORDER BY [ROW_NUMBER]

In plain English:
1.Filtern Sie Ihre Zeilen und verwenden Sie die ROW_NUMBER-Funktion zum hinzufügen von Zeilennummern in der Reihenfolge, die Sie wollen.
2.Filter (1), um nur die Zeilen-Nummern, die Sie möchten, auf Ihrer Seite.
3.Sortieren (2), indem Sie die Nummer der Zeile, die die gleiche wie die Reihenfolge, die Sie wollte (in diesem Fall Name).

Es gibt im wesentlichen zwei Möglichkeiten die Paginierung in der Datenbank (ich bin davon ausgegangen, dass Sie SQL Server):

Mit VERSATZ

Andere haben erklärt, wie die ROW_NUMBER() OVER() ranking-Funktion kann verwendet werden, um Seiten.Es ist erwähnenswert, dass SQL Server 2012 endlich die Unterstützung für den SQL-standard OFFSET .. FETCH Klausel:

SELECT first_name, last_name, score
FROM players
ORDER BY score DESC
OFFSET 40 ROWS FETCH NEXT 10 ROWS ONLY

Wenn Sie mit SQL Server 2012 und rückwärts-Kompatibilität ist nicht ein Problem, sollten Sie es wahrscheinlich vorziehen, diese Klausel, wie es ausgeführt wird optimal von SQL Server in Sonderfällen.

Die Verwendung der SEEK-Methode

Es ist eine ganz andere, viel schnellere, aber weniger bekannte Möglichkeit zur Durchführung von paging in SQL.Dies wird Häufig als die "seek-Methode", wie beschrieben in dieser blog-post hier.

SELECT TOP 10 first_name, last_name, score
FROM players
WHERE (score < @previousScore)
   OR (score = @previousScore AND player_id < @previousPlayerId)
ORDER BY score DESC, player_id DESC

Die @previousScore und @previousPlayerId Werte sind die jeweiligen Werte des letzten Datensatzes aus dem vorherigen Seite.Diese können Sie Holen sich die "nächste" Seite.Wenn die ORDER BY Richtung ASC, verwenden Sie einfach > statt.

Mit der oben beschriebenen Methode können Sie nicht sofort zur Seite springen 4 ohne zuerst holte den vorherigen 40 records.Aber oft, Sie nicht wollen, zu springen, so weit jedenfalls.Stattdessen erhalten Sie eine viel schnellere Abfrage, die möglicherweise zum abrufen von Daten in konstanter Zeit, je nach der Indizierung.Plus, Ihre Seiten bleiben "stabil", egal, ob die zugrunde liegenden Daten geändert haben (z.B.auf Seite 1, während Sie sind auf Seite 4).

Dies ist der beste Weg zum implementieren von paging, wenn lazy loading, mehr Daten in web-Anwendungen, zum Beispiel.

Beachten Sie, dass die "seek-Methode" ist auch als keyset-paging.

LINQ kombiniert mit lambda-Ausdrücke und anonyme Klassen .Net 3.5 enorm vereinfacht diese Art der Sache.

Das Abfragen der Datenbank:

var customers = from c in db.customers
                join p in db.purchases on c.CustomerID equals p.CustomerID
                where p.purchases > 5
                select c;

Anzahl der Datensätze pro Seite:

customers = customers.Skip(pageNum * pageSize).Take(pageSize);

Sortierung nach jeder Spalte:

customers = customers.OrderBy(c => c.LastName);

Immer nur ausgewählte Felder von server:

var customers = from c in db.customers
                join p in db.purchases on c.CustomerID equals p.CustomerID
                where p.purchases > 5
                select new
                {
                    CustomerID = c.CustomerID,
                    FirstName = c.FirstName,
                    LastName = c.LastName
                };

Dies schafft eine statisch typisierte anonyme Klasse, in die Sie zugreifen können seine Eigenschaften:

var firstCustomer = customer.First();
int id = firstCustomer.CustomerID;

Ergebnisse von Abfragen sind faul geladen durch Standard, so dass Sie nicht sprechen auf die Datenbank, bis Sie tatsächlich benötigen die Daten.LINQ in .Net sich ebenfalls stark vereinfacht-updates, indem Sie einen datacontext jegliche änderungen, die Sie vorgenommen haben, und aktualisiert dabei nur die Felder, die Sie ändern.

Oracle Lösung:

select * from (
    select a.*, rownum rnum from (
        YOUR_QUERY_GOES_HERE -- including the order by
    ) a
    where rownum <= MAX_ROW
 ) where rnum >= MIN_ROW

Es gibt ein paar Lösungen, die ich mit meinem MS SQL 2005.

Einer von Ihnen ist ROW_NUMBER().Aber persönlich, ich weiß nicht, wie ROW_NUMBER (), weil es nicht funktioniert für große Ergebnisse (DB denen ich arbeite, ist wirklich sehr groß-mehr als 1 TB Daten, die laufen Tausende von Abfragen in der Sekunde-Sie wissen-die großen social-networking-site).

Hier sind meine Lieblings-Lösung.

Ich werde eine Art pseudo-code von T-SQL.

Let ' s find Seite 2 von Benutzern sortiert nach Vorname, Nachname, in denen jede Seite hat 10 Einträge.

@page = 2 -- input parameter
@size = 10 -- can be optional input parameter

if @page < 1 then begin
    @page = 1 -- check page number
end
@start = (@page-1) * @size + 1 -- @page starts at record no @start

-- find the beginning of page @page
SELECT TOP (@start)
    @forename = forename,
    @surname = surname
    @id = id
FROM
    users
ORDER BY
    forename,
    surname,
    id -- to keep correct order in case of have two John Smith.

-- select @size records starting from @start
SELECT TOP (@size)
    id,
    forename,
    surname
FROM
    users
WHERE
    (forename = @forename and surname = @surname and id >= @id) -- the same name and surname, but bigger id
    OR (forename = @forename and surname > @surname) -- the same name, but bigger surname, id doesn't matter
    OR (forename > @forename) -- bigger forename, the rest doesn't matter
ORDER BY
    forename,
    surname,
    id

Eigentlich LINQ-hat Überspringen und Nehmen Sie Methoden, die kombiniert werden können, um auszuwählen, welche Datensätze abgerufen werden.

Überprüfen Sie diese heraus.

Für die DB: Paginierung In SQL Server 2005

Es ist eine Diskussion über dieses Hier

Die Technik wird Seitenzahl 100.000 von einem 150.000-line-Datenbank in 78ms

Mit optimizer wissen und SET ROWCOUNT, der erste EmployeeID in der Seite, die angefordert wird, ist gespeichert in eine lokale variable für einen Ausgangspunkt.Stellen Sie ROWCOUNT ein, um die maximale Anzahl von Datensätzen, die beantragt, @maximumRows.Dies ermöglicht paging die Ergebnismenge in eine viel mehr effiziente Weise.Mit dieser Methode nutzt die Vorteile der bereits bestehenden Indizes auf der Tabelle, da geht es direkt zu den Basis-Tisch und nicht auf eine lokal erstellte Tabelle.

Ich fürchte, ich bin nicht in der Lage zu beurteilen, ob es besser ist als die aktuelle akzeptierte Antwort.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top