在SQL Server 2000、2005、2008、2012中分页结果的最佳方法(性能方面)是什么?如果你还想获得结果的总数(在分页之前)?


当前回答

最后,微软SQL Server 2012发布了,我真的很喜欢它的简单的分页,你不需要使用复杂的查询,就像这里回答的。

要获得接下来的10行,只需运行这个查询:

SELECT * FROM TableName ORDER BY id OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;

https://learn.microsoft.com/en-us/sql/t-sql/queries/select-order-by-clause-transact-sql#using-offset-and-fetch-to-limit-the-rows-returned

使用时需要考虑的要点:

ORDER BY是强制使用OFFSET…获取子句。 OFFSET子句在FETCH中是强制的。你不能使用ORDER BY… 取回。 在同一个查询中,TOP不能与OFFSET和FETCH组合使用 表达式。

其他回答

令人难以置信的是,没有其他答案提到在所有SQL Server版本中进行分页的最快方法。对于大页码,偏移量可能非常慢。在SQL中有一种完全不同的更快的分页方法。这通常被称为“查找方法”或“键集分页”,如本文所述。

SELECT TOP 10 first_name, last_name, score, COUNT(*) OVER()
FROM players
WHERE (score < @previousScore)
   OR (score = @previousScore AND player_id < @previousPlayerId)
ORDER BY score DESC, player_id DESC

"seek谓词"

@previousScore和@previousPlayerId值分别是前一页中最后一条记录的值。这允许你获取“下一页”。如果ORDER BY方向为ASC,只需使用>即可。

使用上述方法,如果不先获取之前的40条记录,就不能立即跳转到第4页。但通常情况下,你并不想跳得那么远。相反,您将获得一个更快的查询,可能能够在常数时间内获取数据,这取决于您的索引。另外,你的页面保持“稳定”,无论底层数据是否发生变化(例如,在第1页,而你在第4页)。

例如,当在web应用程序中延迟加载更多数据时,这是实现分页的最佳方法。

注意,“seek方法”也称为键集分页。

分页前的记录总数

COUNT(*) OVER()窗口函数将帮助您计算“分页前”的总记录数量。如果您使用的是SQL Server 2000,则必须对COUNT(*)进行两次查询。

在sql server 2012中分页的最佳方法是在存储过程中使用offset和fetch next。 OFFSET关键字-如果对order by子句使用OFFSET,则查询将跳过OFFSET n Rows中指定的记录数。

FETCH NEXT关键字-当我们使用FETCH NEXT与一个order by子句,它将返回你想要显示在分页的行数,没有Offset,那么SQL将生成一个错误。 下面是一个例子。

create procedure sp_paging
(
 @pageno as int,
 @records as int
)
as
begin
declare @offsetcount as int
set @offsetcount=(@pageno-1)*@records
select id,bs,variable from salary order by id offset @offsetcount rows fetch Next @records rows only
end

您可以像下面这样执行它。

exec sp_paging 2,3

您没有指定使用的语言或驱动程序。因此我只是抽象地描述它。

创建可滚动的结果集/数据集。这要求在表上有一个(多个)主表 跳到最后 请求行数 跳转到页面的开头 滚动行直到页面的末尾

获取结果总数和分页是两个不同的操作。对于这个示例,让我们假设您正在处理的查询是

SELECT * FROM Orders WHERE OrderDate >= '1980-01-01' ORDER BY OrderDate

在这种情况下,您将使用以下命令确定结果的总数:

SELECT COUNT(*) FROM Orders WHERE OrderDate >= '1980-01-01'

...这可能看起来效率很低,但实际上性能很好,假设所有索引等都正确设置。

接下来,要以分页方式返回实际结果,下面的查询将是最有效的:

SELECT  *
FROM    ( SELECT    ROW_NUMBER() OVER ( ORDER BY OrderDate ) AS RowNum, *
          FROM      Orders
          WHERE     OrderDate >= '1980-01-01'
        ) AS RowConstrainedResult
WHERE   RowNum >= 1
    AND RowNum < 20
ORDER BY RowNum

这将返回原始查询的第1-19行。这里很酷的事情是,尤其是对于web应用程序,你不需要保留任何状态,除了要返回的行号。

http://www.codeproject.com/KB/aspnet/PagingLarge.aspx上有关于不同分页技术的很好的概述

我经常在SQL Server 2000中使用ROWCOUNT方法(也可以在2005和2008中使用,只测量与ROW_NUMBER相比的性能),它的速度非常快,但你需要确保排序的列(大多数)具有唯一的值。