使用Row_Number在Sql Server 2008中实现表分页是否有任何性能问题?

maj*_*tor 13 sql-server paging

我想使用此方法实现表分页:

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;
Run Code Online (Sandbox Code Playgroud)

有什么我应该知道的吗?表有数百万条记录.

谢谢.

编辑: 使用建议的MAXROWS方法一段时间后(这真的非常快)我不得不切换回ROW_NUMBER方法,因为它具有更大的灵活性.到目前为止,我对它的速度也非常满意(我正在使用包含10列的超过1M记录的View).要使用任何类型的查询,我使用以下修改:

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
Run Code Online (Sandbox Code Playgroud)

如果您使用此过程,请确保您阻止sql注入.

Aar*_*ght 19

我实际上已经写了几次这个; ROW_NUMBER到目前为止,它是最灵活和易于使用的,性能也很好,但对于超大型数据集而言,它并不总是最好的.SQL Server仍然需要对数据进行排序,排序可能会非常昂贵.

这里有一种不同的方法,使用几个变量,SET ROWCOUNT并且只要你有正确的索引,它就非常快.它已经过时了,但就我所知,它仍然是效率最高的.基本上你可以做一个完全天真SELECTSET ROWCOUNT,SQL Server能够优化大部分实际工作; 计划和成本最终类似于两个MAX/ MIN查询,这通常比单个窗口查询更快.对于非常大的数据集,其运行时间不到1/10.

话虽如此,我仍然总是建议ROW_NUMBER当人们询问如何实现分页或分组最大值等内容时,因为它使用起来非常简单.如果你开始注意减速,我只会开始寻找上面的替代品ROW_NUMBER.


Joh*_*ers 8

最近,我在具有星型模式的数据仓库环境中使用了分页.当我将CTE限制为仅查询确定所需的行时,我发现性能非常好ROW_NUMBER.我让CTE返回ROW_NUMBER加上其他行的主键,这有助于确定行号.

在主查询中,我引用了ROW_NUMBERfor paging,然后根据CTE中的其他主键连接到其他表.我发现连接仅在满足WHERE外部查询中的子句的行上执行,从而节省了大量时间.