¿Cómo funciona la paginación con ROW_NUMBER en SQL Server?

13

Tengo una Employeetabla que tiene un millón de registros. Tengo el siguiente SQL para paginar datos en una aplicación web. Esta funcionando bien Sin embargo, lo que veo como un problema es que la tabla derivada tblEmployeeselecciona todos los registros de la Employeetabla (para crear los MyRowNumbervalores).

Creo que esto provoca la selección de todos los registros en la Employeetabla.

¿Realmente funciona así? ¿O SQL Server está optimizado para seleccionar solo los 5 registros de la Employeetabla original también?

DECLARE @Index INT;
DECLARE @PageSize INT;

SET @Index = 3;
SET @PageSize = 5;

SELECT *  FROM
  (SELECT  ROW_NUMBER() OVER (ORDER BY EmpID asc) as MyRowNumber,*
  FROM Employee) tblEmployee
WHERE MyRowNumber BETWEEN ( ((@Index - 1) * @PageSize )+ 1) AND @Index*@PageSize 
LCJ
fuente
3
Consulte sqlservercentral.com/articles/T-SQL/66030 y, lo que es más importante, la discusión que sigue .
Aaron Bertrand

Respuestas:

17

Una alternativa a la prueba podría ser:

;WITH x AS (SELECT EmpID, k = ROW_NUMBER() OVER (ORDER BY EmpID) FROM dbo.Emp)
SELECT e.columns
FROM x INNER JOIN dbo.Emp AS e
ON x.EmpID = e.EmpID
WHERE x.k BETWEEN (((@Index - 1) * @PageSize) + 1) AND @Index * @PageSize
ORDER BY ...;

Sí, golpeó la tabla dos veces, pero en el CTE donde escanea toda la tabla solo está agarrando la clave, no TODOS los datos. Pero realmente deberías mirar este artículo:

http://www.sqlservercentral.com/articles/T-SQL/66030/

Y la discusión de seguimiento:

http://www.sqlservercentral.com/Forums/Topic672980-329-1.aspx

En SQL Server 2012, por supuesto, puede usar la nueva OFFSET/ FETCH NEXTsintaxis:

;WITH x AS 
(
  SELECT EmpID FROM dbo.Emp
    ORDER BY EmpID
    OFFSET  @PageSize * (@Index - 1) ROWS
    FETCH NEXT @PageSize ROWS ONLY
)
SELECT e.columns
FROM x INNER JOIN dbo.Emp AS e
ON x.EmpID = e.EmpID
ORDER BY ...; 
Aaron Bertrand
fuente
Sin embargo, debe tenerse en cuenta que OFFSET / FETCH NEXT no ofrece ningún beneficio de rendimiento sobre el método CTE
Akash
2
@Akash, ¿has probado esto a fondo? He observado algunas diferencias en el plan, pero no mencioné específicamente nada sobre el rendimiento porque no he realizado ninguna prueba exhaustiva. Incluso si el rendimiento es el mismo, la sintaxis es un poco menos engorrosa. Hice un blog al respecto aquí: sqlblog.com/blogs/aaron_bertrand/archive/2010/11/10/…
Aaron Bertrand
1
Ah, tienes razón, hay una diferencia de rendimiento. Había leído esto: blogs.technet.com/b/dataplatforminsider/archive/2011/11/01/… donde no menciona la diferencia, pero acabo de ver channel9.msdn.com/posts/SQL11UPD03-REC-02 donde muestra allí mucha diferencia .. (aunque en la subestimación de audio la diferencia de rendimiento)
Akash
2

Aunque es posible que no conozca el mecanismo detrás de esto, puede probarlo usted mismo comparando el rendimiento de su consulta con: seleccione * de Empleado.

Las versiones más recientes de SQL Server hacen un buen trabajo de optimización, pero puede depender de varios factores.

El rendimiento de su función ROW_NUMBER dependerá de la cláusula Order By. En su ejemplo, la mayoría diría que EmpID es la clave principal.

Hay algunas cláusulas where que son tan complejas y / o están mal codificadas o indexadas, que es mejor que solo devuelva todo el conjunto de datos (es raro y se puede arreglar). Usar ENTRE tiene problemas.

Antes de asumir que sería mejor devolver todas las filas a su aplicación y dejar que lo resuelva, debe trabajar para optimizar su consulta. Consulta las estimaciones. Pregunte al analizador de consultas. Prueba algunas alternativas.

JeffO
fuente
2

Sé que la pregunta es con respecto a row_number () pero quiero agregar una nueva característica de sql server 2012. En sql server 2012 se introdujo la nueva característica OFFSET Fetch y es muy rápida que row_number (). Lo he usado y me da buenos resultados, espero que ustedes también llenen la misma experiencia.

Encontré un ejemplo en http://blogfornet.com/2013/06/sql-server-2012-offset-use/

lo cual es útil Espero que también te ayude a implementar nuevas funciones ...

Sam Raj
fuente
-2

No creo que evalúe devolver todas las filas en la tabla original. El servidor SQL optimiza. De lo contrario, tomará una gran cantidad de tiempo seleccionar un millón de entradas. Actualmente estoy usando esto y es mucho más rápido que seleccionar todas las filas. Entonces, seguro no obtiene todas las filas. Sin embargo, es más lento que solo buscar las primeras cinco filas, probablemente debido al tiempo que toma ordenar

usuario3688672
fuente
-2
DECLARE @PageIndex int;
DECLARE @PageSize int;
SET @PageIndex = 4;
SET @PageSize = 5;
;With ranked AS   --- Or you can make it a view
(
   SELECT ROW_NUMBER() OVER(ORDER BY IdentityId) AS RowNum,  *
   FROM logeventnew
)
SELECT *   --Your fields here
FROM Ranked
WHERE RowNum BETWEEN ((@PageIndex - 1) * @PageSize + 1)
    AND (@PageIndex * @PageSize)
ORDER BY IdentityId
Agnel Amodia
fuente
44
¿Podría ampliar su respuesta? La pregunta era sobre cómo funciona la paginación internamente en SQL Server, es decir, qué hace el motor de la base de datos para cumplir con la solicitud. Desafortunadamente, a partir de ahora, su respuesta no aborda la preocupación real.
Mr.Brownstone