当前位置:  开发笔记 > 后端 > 正文

在SQL Server中分页结果的最佳方法是什么

如何解决《在SQLServer中分页结果的最佳方法是什么》经验,为你挑选了7个好方法。

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



1> Õzbek..:

最后,Microsoft SQL Server 2012发布了,我真的很喜欢它的分页简单,你不必使用这里回答的复杂查询.

要获取接下来的10行,只需运行此查询:

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

http://technet.microsoft.com/en-us/library/gg699618.aspx

使用时需要考虑的要点:

ORDER BY必须使用OFFSET和FETCH子句.

FETCH强制使用OFFSET子句.你永远不能使用,ORDER BY ... FETCH.

TOP不能与OFFSET和FETCH在同一查询表达式中组合使用.


还在等待'LISTAGG()`/`GROUP_CONCAT()`.
@Jon,链接的博客文章不具代表性,从某种意义上说,它通过查找id列的值来返回页面结果进行比较.
羞耻性是如此糟糕http://www.mssqlgirl.com/paging-function-performance-in-sql-server-2012.html

2> mdb..:

获得结果总数和分页是两种不同的操作.为了这个例子,让我们假设您正在处理的查询是

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应用程序,是你不必保留任何状态,除了要返回的行号.


请注意,SQL Server 2000中不存在ROW_NUMBER()
微软为SQL 2012添加了一项新功能,使分页与MySQL类似.请点击此链接了解具体方法.这是一篇有趣的文章:http://dbadiaries.com/new-t-sql-features-in-sql-server-2012-offset-and-fetch
这会返回内部查询中的所有行,然后根据外部查询进行过滤吗?例如:内部查询返回100,000,外部查询返回20.
@SoftwareGeek:将其视为返回流的子查询(内部查询),然后读取该流,直到满足外部WHERE子句.如何与行相关,完全取决于查询,但优化器通常在最小化该数量方面做得非常好.在这方面,使用SQL Server Management Studio中的图形执行计划查看器(使用查询/包括实际执行计划)是非常有教育意义的.
好吧,如果你在内部选择中被公开(如你有内部联接),你怎么使用不同因为RowNumber是不同的,它不起作用

3> Lukas Eder..:

令人难以置信的是,没有其他答案提到在所有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

"寻求谓词"

@previousScore@previousPlayerId值是来自前一页的最后一条记录的相应值.这允许您获取"下一页".如果ORDER BY方向是ASC,只需使用>.

使用上述方法,您无法在未先读取前40条记录的情况下立即跳转到第4页.但通常情况下,你不想跳得那么远.相反,您可以获得更快的查询,该查询可能能够在固定时间内获取数据,具体取决于您的索引.此外,无论基础数据是否发生变化,您的页面都将保持"稳定"状态(例如,在第4页上,当您在第4页时).

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

注意,"搜索方法"也称为键集分页.

分页前的总记录

COUNT(*) OVER()窗口功能将帮助你"分页之前"算的总记录数.如果您使用的是SQL Server 2000,则必须使用两个查询COUNT(*).


我有三个问题的搜索方法.[1]用户无法跳转到页面.[2]它假定顺序键,即如果有人删除了3行,那么我得到一个7项而不是10页的页面.`RowNumber`每页给我一个10项.[3]它不适用于假设`pagenumber`和`pagesize`的现有网格.
@Junto:键集分页并不适合所有情况.它绝对不适用于数据网格.但它非常适合无限滚动Facebook Feed页面等场景.如果在顶部添加新帖子无关紧要,则在您向下滚动时,您的后续Feed帖子会正确添加到底部.这个完美的用法示例......这样的事情会更加难以实现,只能使用数字来实现偏移限制/获取.
我不得不同意Junto.这种方法完全排除了一个客户端,该客户端具有相当标准的分页ui"Previous 1 2 3(4)5 6 Next",用户可以在其中跳过.根据我的经验,这不是一个优势......
@ user960567:在性能方面,无论您是使用SQL标准`OFFSET .. FETCH`还是使用之前的`ROW_NUMBER()`技巧实现偏移分页,键集分页总是会超过偏移分页.
键集分页文章[这里](http://use-the-index-luke.com/no-offset)

4> 小智..:

从SQL Server 2012开始,我们可以使用OFFSETFETCH NEXTClause来实现分页.

试试这个,对于SQL Server:

在SQL Server 2012中,ORDER BY子句中添加了一项新功能,用于查询集合数据的优化,使用T-SQL以及SQL Server中的整个执行计划编写任何人的数据分页,使工作更轻松.

在T-SQL脚本下面,使用与前一个示例中使用的逻辑相同的逻辑.

--CREATING A PAGING WITH OFFSET and FETCH clauses IN "SQL SERVER 2012"
DECLARE @PageNumber AS INT, @RowspPage AS INT
SET @PageNumber = 2
SET @RowspPage = 10 
SELECT ID_EXAMPLE, NM_EXAMPLE, DT_CREATE
FROM TB_EXAMPLE
ORDER BY ID_EXAMPLE
OFFSET ((@PageNumber - 1) * @RowspPage) ROWS
FETCH NEXT @RowspPage ROWS ONLY;

TechNet:使用SQL Server分页查询



5> liggett78..:

有关不同分页技术的概述,请访问http://www.codeproject.com/KB/aspnet/PagingLarge.aspx

我经常使用ROWCOUNT方法主要使用SQL Server 2000(也可以使用2005和2008,只测量性能与ROW_NUMBER相比),它快速闪电,但你需要确保排序的列(主要是) )独特的价值观.



6> Dinesh Rabar..:

MSDN:ROW_NUMBER(Transact-SQL)

返回结果集分区中行的序号,从1开始,每个分区的第一行.

以下示例按OrderDate的顺序返回编号为50到60的行.

WITH OrderedOrders AS
(
    SELECT
        ROW_NUMBER() OVER(ORDER BY FirstName DESC) AS RowNumber, 
        FirstName, LastName, ROUND(SalesYTD,2,1) AS "Sales YTD"
    FROM [dbo].[vSalesPerson]
) 
SELECT RowNumber, 
    FirstName, LastName, Sales YTD 
FROM OrderedOrders 
WHERE RowNumber > 50 AND RowNumber < 60;
  RowNumber FirstName    LastName               SalesYTD
  --- -----------  ---------------------- -----------------
  1   Linda        Mitchell               4251368.54
  2   Jae          Pak                    4116871.22
  3   Michael      Blythe                 3763178.17
  4   Jillian      Carson                 3189418.36
  5   Ranjit       Varkey Chudukatil      3121616.32
  6   José         Saraiva                2604540.71
  7   Shu          Ito                    2458535.61
  8   Tsvi         Reiter                 2315185.61
  9   Rachel       Valdez                 1827066.71
  10  Tete         Mensa-Annan            1576562.19
  11  David        Campbell               1573012.93
  12  Garrett      Vargas                 1453719.46
  13  Lynn         Tsoflias               1421810.92
  14  Pamela       Ansman-Wolfe           1352577.13



7> Thomas S. Tr..:

对于SQL Server 2000,您可以使用带有IDENTITY列的表变量来模拟ROW_NUMBER():

DECLARE @pageNo int -- 1 based
DECLARE @pageSize int
SET @pageNo = 51
SET @pageSize = 20

DECLARE @firstRecord int
DECLARE @lastRecord int
SET @firstRecord = (@pageNo - 1) * @pageSize + 1 -- 1001
SET @lastRecord = @firstRecord + @pageSize - 1   -- 1020

DECLARE @orderedKeys TABLE (
  rownum int IDENTITY NOT NULL PRIMARY KEY CLUSTERED,
  TableKey int NOT NULL
)

SET ROWCOUNT @lastRecord
INSERT INTO @orderedKeys (TableKey) SELECT ID FROM Orders WHERE OrderDate >= '1980-01-01' ORDER BY OrderDate

SET ROWCOUNT 0

SELECT t.*
FROM Orders t
  INNER JOIN @orderedKeys o ON o.TableKey = t.ID
WHERE o.rownum >= @firstRecord
ORDER BY o.rownum

这种方法可以扩展到具有多列密钥的表,并且不会产生使用OR(跳过索引使用)的性能开销.缺点是如果数据集非常大且一个接近最后一页,则用尽的临时空间量.在这种情况下我没有测试游标性能,但它可能会更好.

请注意,可以针对第一页数据优化此方法.此外,由于TOP不接受SQL Server 2000中的变量,因此使用了ROWCOUNT.

推荐阅读
罗文彬2502852027
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有