从OFFSET/FETCH NEXT获取总行数

Cry*_*lue 79 paging performance sql-server-2012

所以,我有一个函数可以返回一些我希望在我的网站上实现分页的记录.有人建议我使用SQL Server 2012中的Offset/Fetch Next来完成此任务.在我们的网站上,我们有一个区域列出了当时的记录总数和您所在的页面.

之前,我正在获取整个记录集,并能够以编程方式构建分页.但是只使用带有FETCH NEXT X ROWS的SQL方法,我只返回X行,所以我不知道我的总记录集是什么以及如何计算我的最小和最大页面.我能告诉你这样做的唯一方法是调用函数两次并在第一次执行行计数,然后使用FETCH NEXT运行第二行.有没有更好的方法不让我运行查询两次?我试图加快性能,而不是减慢速度.

Jam*_*erg 131

我使用COUNT()OVER()方法遇到了一些性能问题.(我不确定它是否是服务器,因为它需要40秒才能返回10条记录然后没有任何问题.)这种技术在所有条件下都能工作,而不必使用COUNT()OVER()并完成一样:

DECLARE 
    @PageSize INT = 10, 
    @PageNum  INT = 1;

WITH TempResult AS(
    SELECT ID, Name
    FROM Table
), TempCount AS (
    SELECT COUNT(*) AS MaxRows FROM TempResult
)
SELECT *
FROM TempResult, TempCount
ORDER BY TempResult.Name
    OFFSET (@PageNum-1)*@PageSize ROWS
    FETCH NEXT @PageSize ROWS ONLY
Run Code Online (Sandbox Code Playgroud)

  • 如果有可能将COUNT(*)值保存到变量,那真的很棒.我可以将它设置为我的存储过程的OUTPUT参数.有任何想法吗? (28认同)
  • 为什么这么好用?在第一个CTE中,选择所有行,然后通过提取削减.我猜想在第一次CTE中选择所有行会显着减慢速度.无论如何,谢谢你! (3认同)
  • 这非常适合小型数据库,当行数达到数百万时,会花费太多时间。 (2认同)

Aar*_*and 101

您可以使用COUNT(*) OVER()...这是一个使用sys.all_objects以下的快速示例:

DECLARE 
  @PageSize INT = 10, 
  @PageNum  INT = 1;

SELECT 
  name, object_id, 
  overall_count = COUNT(*) OVER()
FROM sys.all_objects
ORDER BY name
  OFFSET (@PageNum-1)*@PageSize ROWS
  FETCH NEXT @PageSize ROWS ONLY;
Run Code Online (Sandbox Code Playgroud)

  • 在包含3,500,000条记录的表中,COUNT(*)OVER()花了1分3秒.James Moberg在下面描述的方法用了13秒来检索相同的数据集.我确信Count Over方法适用于较小的数据集,但是当你开始变得非常大时,它会大大减慢. (41认同)
  • @idx不,那也不是2008 R2的表现,对不起.我从6.5开始就一直在使用SQL Server,我不记得发动机不够聪明的时候只扫描COUNT(*)或COUNT(1)的最窄索引.当然不是自2000年以来.但是,嘿,我有一个2008 R2的实例,你可以在SQLfiddle上设置一个repro来证明你声称存在的这种差异吗?我很乐意尝试. (4认同)
  • 在 sql server 2016 数据库上,搜索一个包含大约 2500 万行的表,对大约 3000 个结果进行分页(有几个连接,包括一个表值函数),这花了几毫秒 - 太棒了! (3认同)
  • @AaronBertrand 真的吗?这必定意味着您要么拥有一个包含所有列的索引,要么自 2008R2 以来已经得到了很大改进。在该版本中, count(*) 按顺序工作,这意味着首先选择 * (如:所有列),然后进行计数。如果执行 count(1),则只需选择一个常量,这比读取实际数据快得多。 (2认同)