Domanda

Molte applicazioni sono griglie per la visualizzazione di dati da una tabella di database di una pagina alla volta.Molti di loro, inoltre, consentire all'utente di scegliere il numero di record per pagina ordina per ogni colonna, e navigare avanti e indietro attraverso i risultati.

Che cosa è un buon algoritmo per realizzare questo modello senza portare l'intera tabella per il cliente e quindi il filtraggio dei dati sul client.Come si fa a portare solo i record che si desidera visualizzare all'utente?

Non LINQ semplificare la soluzione?

È stato utile?

Soluzione

Su MS SQL Server 2005 e al di sopra, ROW_NUMBER() sembra funzionare:

T-SQL:Paging con 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;

Altri suggerimenti

Mi raccomando utilizzando LINQ, o tenta di copiare quello che fa.Ho un'applicazione in cui io uso il LINQ Prendere e Ignora i metodi per recuperare i dati di paging.Codice simile a questo:

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

Esecuzione di SQL Server Profiler rivela che LINQ è la conversione di questa query in SQL simile a:

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 un inglese semplice:
1.Filtrare le righe e utilizzare la funzione ROW_NUMBER per aggiungere i numeri di riga nell'ordine che si desidera.
2.Filtro (1) per restituire solo i numeri di riga che si desidera sulla pagina.
3.Sort (2) dal numero della riga, che è la stessa che hai voluto (in questo caso, per Nome).

Ci sono essenzialmente due modi di fare la paginazione nel database (sto supponendo che si sta utilizzando SQL Server):

L'utilizzo di OFFSET

Altri hanno spiegato come il ROW_NUMBER() OVER() classifica funzione può essere utilizzata per eseguire pagine.Vale la pena ricordare che SQL Server 2012, infine, incluso il supporto per SQL standard OFFSET .. FETCH clausola:

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

Se si utilizza SQL Server 2012 e retro-compatibilità non è un problema, probabilmente si dovrebbe preferire questa clausola verrà eseguito in modo ottimale da SQL Server in casi particolari.

Utilizzando il Metodo di ricerca

C'è una completamente diversa, molto più veloce, ma meno noto modo per eseguire la chiamata in SQL.Questo è spesso chiamato il "metodo di ricerca", come descritto in in questo post qui.

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

Il @previousScore e @previousPlayerId i valori sono i rispettivi valori dell'ultima registrazione dalla pagina precedente.Questo consente di recuperare il "next page".Se il ORDER BY la direzione è ASC, basta usare semplicemente > invece.

Con il metodo di cui sopra, non è possibile passare immediatamente a pagina 4 senza aver prima recuperato 40 giorni precedenti record.Ma spesso, non si vuole saltare lontano comunque.Invece, si ottiene un più veloce query che potrebbe essere in grado di recuperare i dati in tempo costante, a seconda di indicizzazione.Inoltre, le pagine rimangono "stabili", non importa se i dati sottostanti (ad es.a pagina 1, mentre sei a pagina 4).

Questo è il modo migliore per implementare il paging durante il caricamento lazy più dati in applicazioni web, per esempio.

Nota, il "metodo di ricerca" è anche chiamato keyset di paging.

LINQ combinato con le espressioni lambda e anonimo classi .Net 3.5 molto semplifica questo genere di cose.

L'interrogazione di database:

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

Numero di record per pagina:

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

Ordinamento per colonna:

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

Ottenere solo i campi selezionati dal 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
                };

Questo crea un staticamente tipizzato classe anonima in cui è possibile accedere alle sue proprietà:

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

I risultati di una query sono pigro-caricato di default, in modo che non stanno parlando al database fino a quando è effettivamente necessario i dati.LINQ in .Net, inoltre, semplifica notevolmente gli aggiornamenti mantenendo un datacontext di eventuali modifiche, e solo l'aggiornamento di campi che si modifica.

Soluzione Oracle:

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

Ci sono alcune soluzioni che utilizzo con MS SQL 2005.

Uno di loro è ROW_NUMBER().Ma, personalmente, non mi piace ROW_NUMBER() perché non funziona per i grandi risultati (DB che ho il lavoro è davvero grande, ha più di 1 TB di dati in grado di eseguire migliaia di query nella seconda rapinatori grande sito di social networking).

Ecco la mia soluzione preferita.

Io la utilizzo sorta di pseudo codice T-SQL.

Vediamo pagina 2 di utenti ordinati per nome, cognome, dove ogni pagina è di 10 record.

@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

In realtà, LINQ è Saltare e Prendere metodi che possono essere combinati per scegliere i record vengono recuperati.

Controllare quelli fuori.

Per il DB: Paginazione In SQL Server 2005

C'è una discussione su questo Qui

La tecnica ottiene il numero di pagina 100.000 da una linea di 150.000 database in 78ms

Utilizzando optimizer conoscenza e SET ROWCOUNT, il primo Impiegato della pagina che viene richiesto è memorizzato in una variabile locale per un punto di partenza.A quel punto, SET ROWCOUNT per il numero massimo di record che è richiesto in @maximumRows.Questo permette di paging il set di risultati in modo più efficiente.Utilizzando questo metodo si avvale anche di pre-esistenti indici sulla tabella come va direttamente alla tabella di base e non localmente, la tabella creata.

Ho paura io non sono in grado di giudicare se è meglio l'attuale accettato di rispondere.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top