我想用这个方法实现表格分页:
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 注入。
实际上我已经写过好几次了;
ROW_NUMBER
是迄今为止最灵活且易于使用的,并且性能也好,但对于极大的数据集,它并不总是“最好的”。 SQL Server 仍然需要对数据进行排序,并且排序可能会变得相当昂贵。
这里有一种不同的方法,它使用几个变量和SET ROWCOUNT
并且速度非常快,前提是您有正确的索引。 它很旧,但据我所知,它仍然是最有效的。 基本上你可以用
SELECT
做一个完全简单的 SET ROWCOUNT
,SQL Server 能够优化大部分实际工作;计划和成本最终类似于两个 MAX
/MIN
查询,这通常比单个窗口查询要快得多。 对于非常大的数据集,运行时间不到 1/10。话虽如此,当人们询问如何实现分页或分组最大值之类的东西时,我仍然总是推荐
ROW_NUMBER
,因为它非常容易使用。 如果您开始注意到
ROW_NUMBER
速度变慢,我只会开始考虑上述替代方案。ROW_NUMBER
所需的行时,性能非常好。我让 CTE 返回
ROW_NUMBER
以及有助于确定行号的其他行的主键。在主查询中,我引用了
ROW_NUMBER
进行分页,然后根据CTE中的其他主键连接到其他表。我发现只对满足外部查询中
WHERE
子句的行执行连接,节省了大量时间。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