在Sql Server 2008中使用Row_Number实现表分页有性能问题吗?

问题描述 投票:0回答:3

我想用这个方法实现表格分页:

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;

有什么我应该注意的吗? 表有数百万条记录。

谢谢。

编辑: 使用建议的

MAXROWS
方法一段时间后(效果真的非常快),我不得不切换回
ROW_NUMBER
方法,因为它具有更大的灵活性。到目前为止,我也对其速度感到非常满意(我正在使用具有超过 100 万条记录和 10 列的 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

如果您使用此过程,请确保您阻止了 SQL 注入。

sql-server pagination
3个回答
20
投票

实际上我已经写过好几次了;

ROW_NUMBER
是迄今为止最灵活且易于使用的,并且性能也,但对于极大的数据集,它并不总是“最好的”。 SQL Server 仍然需要对数据进行排序,并且排序可能会变得相当昂贵。 这里有一种

不同的方法

,它使用几个变量和SET ROWCOUNT并且速度非常快,前提是您有正确的索引。 它很旧,但据我所知,它仍然是最有效的。 基本上你可以用

SELECT
做一个完全简单的
SET ROWCOUNT
,SQL Server 能够优化大部分实际工作;计划和成本最终类似于两个
MAX
/
MIN
查询,这通常比单个窗口查询要快得多。 对于非常大的数据集,运行时间不到 1/10。

话虽如此,当人们询问如何实现分页或分组最大值之类的东西时,我仍然总是推荐

ROW_NUMBER

,因为它非常容易使用。 如果您开始注意到

ROW_NUMBER
速度变慢,我只会开始考虑上述替代方案。
    


9
投票
ROW_NUMBER

所需的行时,性能非常好。我让 CTE 返回

ROW_NUMBER
以及有助于确定行号的其他行的主键。

在主查询中,我引用了

ROW_NUMBER

进行分页,然后根据CTE中的其他主键连接到其他表。我发现只对满足外部查询中

WHERE
子句的行执行连接,节省了大量时间。
    


-2
投票

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

	
© www.soinside.com 2019 - 2024. All rights reserved.