2010-02-22 16 views
13

Quiero implementar la paginación tabla usando este método:¿Hay algún problema de rendimiento con Row_Number para implementar la paginación de tabla en 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; 

¿Hay algo que deba tener en cuenta? La tabla tiene millones de registros.

Thx.

EDIT: Después de usar sugerido MAXROWS método durante algún tiempo (que funciona muy muy rápido) que tenía que volver a ROW_NUMBER método debido a su mayor flexibilidad. También estoy muy contento con su velocidad hasta el momento (estoy trabajando con View con más de 1 millón de registros con 10 columnas). Para utilizar cualquier tipo de consulta que utilizo siguiente modificación:

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 

Si se utiliza este procedimiento, asegúrese de u evitarse la inyección de SQL.

+0

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

+0

Pony, no soy muy contento con esa respuesta, sobre todo porque ni siquiera menciona Row_Number() ..... La pregunta es, una vez más: Estoy usando Row_Number().¿Qué me puedes decir sobre su rendimiento en comparación con otros métodos (por lo tanto, no me ofrezcas otro método) – majkinetor

+2

BTW, Pony Encuentro comentarios como este muy groseros. Estoy seguro de que sé cuál es la buena respuesta para mi pregunta, no necesito que me digas eso. Típico amdin BS. – majkinetor

Respuesta

19

He escrito sobre esto algunas veces en realidad; ROW_NUMBER es de lejos el más flexible y fácil de usar, y el rendimiento es bueno, pero para conjuntos de datos extremadamente grandes no siempre es el mejor. SQL Server aún necesita ordenar los datos y el género puede ser bastante costoso.

Hay un different approach here que usa un par de variables y SET ROWCOUNT y es extremadamente rápido, siempre que tenga los índices correctos. Es viejo, pero hasta donde yo sé, sigue siendo el más eficiente. Básicamente puede hacer un SELECT totalmente ingenuo con SET ROWCOUNT y SQL Server puede optimizar la mayor parte del trabajo real; el plan y el costo terminan siendo similares a dos consultas MAX/MIN, que suelen ser mucho más rápidas que una sola consulta de ventanas. Para conjuntos de datos muy grandes, esto se ejecuta en menos de 1/10 parte del tiempo.

Dicho esto, siempre recomiendo ROW_NUMBER cuando las personas preguntan sobre cómo implementar cosas como paginación o máximos agrupados, debido a lo fácil que es usar. Solo comenzaría a buscar alternativas como la anterior si comienza a notar desaceleraciones con ROW_NUMBER.

+0

Primera respuesta aceptable. Gracias m8. No necesito lo mejor de lo mejor. Necesito bien. – majkinetor

+0

Estaba usando este método con ROWCOUNT y estoy muy contento con él, es extremadamente rápido. Sin embargo, no puedo hacer que funcione cuando tengo una instrucción ORDER BY personalizada con columnas que no son de identidad. ¿Conoces una forma de evitarlo? – majkinetor

+0

@majkinetor: ¿Quiere decir simplemente que desea ordenar/página por un campo que no sea el ID, o que la tabla no tiene una columna de ID ni una clave secuencial? – Aaronaught

8

Recientemente, utilicé la búsqueda en un entorno de depósito de datos con un esquema en estrella. Descubrí que el rendimiento fue muy bueno cuando restringí el CTE para que solo consultara las filas necesarias para determinar el ROW_NUMBER. Hice que el CTE devolviera el ROW_NUMBER más las claves principales de las otras filas que ayudaron a determinar el número de fila.

En la consulta principal, hice referencia al ROW_NUMBER para buscar y luego unirme a las otras tablas basadas en las otras claves principales del CTE. Descubrí que las uniones solo se realizaban en las filas que cumplían la cláusula WHERE en la consulta externa, lo que ahorraba una gran cantidad de tiempo.

+0

Tengo una sola tabla solamente. – majkinetor

+1

Eso debería hacerlo aún menos problemático. Pruébalo, luego mira el plan de ejecución. –

+0

Thx por sus comentarios. – majkinetor

-2

prueba esta solución, tal vez es mejor. cambia esto con tu necesidad por favor.

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

Copiando toda la tabla en una tabla temporal ... ¿sin índice? Sí, va a ser lento. Reeeeal lento. Es difícil imaginar un peor enfoque, TBH. – Aaronaught

+0

Además, observe el problema "Row_Number" en la pregunta. Aunque no me parece útil (sin ofender), te daré una ventaja solo para hacer felices a los Ponnies de OMG y sus amigos. – majkinetor

+1

Te escribo esto por ayudar a un ser humano. :) –

Cuestiones relacionadas