2010-02-22 9 views
13

Voglio realizzare tavolo paginazione con questo metodo:Esiste un problema di prestazioni che utilizza Row_Number per implementare il paging delle tabelle in Sql Server 2008?

SET @PageNum = 2; 
SET @PageSize = 10; 

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

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

C'è qualcosa che dovrei essere a conoscenza? La tabella ha milioni di record.

Thx.

EDIT: Dopo aver utilizzato suggerito MAXROWS metodo per un certo tempo (che funziona davvero molto veloce) ho dovuto tornare alla ROW_NUMBER metodo a causa della sua maggiore flessibilità. Sono anche molto contento della sua velocità fino ad ora (sto lavorando con View con più di 1 milione di record con 10 colonne). Per utilizzare qualsiasi tipo di domanda che uso seguente modifica:

PROCEDURE [dbo].[PageSelect] 
(
    @Sql nvarchar(512), 
    @OrderBy nvarchar(128) = 'Id', 
    @PageNum int = 1, 
    @PageSize int = 0  
) 
AS 
BEGIN 
SET NOCOUNT ON 

Declare @tsql as nvarchar(1024) 
Declare @i int, @j int 

if (@PageSize <= 0) OR (@PageSize > 10000) 
    SET @PageSize = 10000 -- never return more then 10K records 

SET @i = (@PageNum - 1) * @PageSize + 1 
SET @j = @PageNum * @PageSize 

SET @tsql = 
'WITH MyTableOrViewRN AS 
(
    SELECT ROW_NUMBER() OVER(ORDER BY ' + @OrderBy + ') AS RowNum 
    ,* 
    FROM MyTableOrView 
    WHERE ' + @Sql + ' 

) 
SELECT * 
    FROM MyTableOrViewRN 
    WHERE RowNum BETWEEN ' + CAST(@i as varchar) + ' AND ' + cast(@j as varchar) 

exec(@tsql) 
END 

Se si utilizza questa procedura assicurarsi u impedito sql injection.

+0

Duplicato esatto: http://stackoverflow.com/questions/1897436/row-number-over-not-fast-enough-with-large-result-set-any-good-solution –

+0

Pony, non sono molto felice con quella risposta, soprattutto perché non menziona nemmeno Row_Number() ..... La domanda è, ancora: sto usando Row_Number().Cosa puoi dirmi delle sue prestazioni rispetto ad altri metodi (quindi, non offrirmi altri metodi) – majkinetor

+2

BTW, Pony Trovo osservazioni come questa molto scortese. Sono sicuro di sapere qual è la buona risposta per la mia domanda, non ho bisogno che tu me lo dica. Tipico amdin BS. – majkinetor

risposta

19

Ho scritto su questo un paio di volte in realtà; ROW_NUMBER è di gran lunga il più flessibile e facile da usare, e le prestazioni sono buone, ma per i set di dati estremamente grandi non è sempre il migliore. SQL Server ha ancora bisogno di ordinare i dati e l'ordinamento può diventare piuttosto costoso.

C'è un different approach here che utilizza un paio di variabili e SET ROWCOUNT ed è estremamente veloce, purché si abbiano gli indici corretti. È vecchio, ma per quanto ne so, è ancora il più efficiente. Fondamentalmente puoi fare un ingenuo con SET ROWCOUNT e SQL Server è in grado di ottimizzare la maggior parte del lavoro reale; il piano e il costo si rivelano simili a due query MAX/MIN, che di solito sono molto più veloci di una sola query con finestre. Per insiemi di dati molto grandi, questo funziona in meno di 1/10 di tempo.

Detto questo, raccomando sempre ROW_NUMBER quando le persone chiedono come implementare cose come paging o groupwise massimi, a causa di quanto sia facile da usare. Vorrei solo iniziare a guardare le alternative come sopra se inizi a notare rallentamenti con ROW_NUMBER.

+0

Prima risposta accettabile. Grazie m8. Non ho bisogno del meglio del meglio. Ho bisogno di bene. – majkinetor

+0

Stavo usando questo metodo con ROWCOUNT e sono molto soddisfatto, è estremamente veloce. Tuttavia, non riesco a farlo funzionare quando ho un'istruzione personalizzata ORDER BY con colonne non identificate. Conosci un modo per aggirarlo? – majkinetor

+0

@majkinetor: Intendi semplicemente che vuoi ordinare/pagina per un campo diverso dall'ID, o che la tabella non ha alcuna colonna ID o chiave sequenziale? – Aaronaught

8

Recentemente, ho utilizzato il paging in un ambiente di data warehouse con uno schema a stella. Ho scoperto che le prestazioni erano molto buone quando ho limitato il CTE per interrogare solo le righe necessarie per determinare lo ROW_NUMBER. Ho avuto il CTE restituire il ROW_NUMBER più le chiavi primarie delle altre righe che hanno contribuito a determinare il numero di riga.

Nella query principale, ho fatto riferimento allo ROW_NUMBER per il paging e quindi unito alle altre tabelle in base alle altre chiavi primarie del CTE. Ho scoperto che i join venivano eseguiti solo sulle righe che soddisfacevano la clausola WHERE nella query esterna, risparmiando molto tempo.

+0

Ho solo una tabella. – majkinetor

+1

Ciò dovrebbe rendere ancora meno un problema. Provalo, quindi guarda il piano di esecuzione. –

+0

Thx per i vostri commenti. – majkinetor

-2

testare questa soluzione, forse è meglio. cambia questo con il tuo bisogno per favore.

CREATE PROCEDURE sp_PagedItems 
    (
    @Page int, 
    @RecsPerPage int 
    ) 
AS 

-- We don't want to return the # of rows inserted 
-- into our temporary table, so turn NOCOUNT ON 
SET NOCOUNT ON 


--Create a temporary table 
CREATE TABLE #TempItems 
(
    ID int IDENTITY, 
    Name varchar(50), 
    Price currency 
) 


-- Insert the rows from tblItems into the temp. table 
INSERT INTO #TempItems (Name, Price) 
SELECT Name,Price FROM tblItem ORDER BY Price 

-- Find out the first and last record we want 
DECLARE @FirstRec int, @LastRec int 
SELECT @FirstRec = (@Page - 1) * @RecsPerPage 
SELECT @LastRec = (@Page * @RecsPerPage + 1) 

-- Now, return the set of paged records, plus, an indiciation of we 
-- have more records or not! 
SELECT *, 
     MoreRecords = 
    (
    SELECT COUNT(*) 
    FROM #TempItems TI 
    WHERE TI.ID >= @LastRec 
    ) 
FROM #TempItems 
WHERE ID > @FirstRec AND ID < @LastRec 


-- Turn NOCOUNT back OFF 
SET NOCOUNT OFF 
+1

Copia l'intera tabella in una tabella temporanea ... senza indice? Sì, sarà lento. Reeeeal lento. Difficile immaginare un approccio peggiore, TBH. – Aaronaught

+0

Inoltre, notare il problema "Row_Number" nella domanda. Anche se non lo trovo utile (senza offesa), ti darò un vantaggio solo per rendere felici OMG Ponnies e i suoi amici. – majkinetor

+1

Ti scrivo per aiutare un umano. :) –

Problemi correlati