分页如何与SQL Server中的ROW_NUMBER一起使用?


13

我有一张Employee有一百万条记录的表。我有以下用于在Web应用程序中分页数据的SQL。一切正常。但是,我认为是一个问题-派生表tblEmployee选择表中的所有记录Employee(以创建 MyRowNumber值)。

我认为,这将导致选择Employee表中的所有记录。

真的有效吗?还是对SQL Server进行了优化以从原始Employee表中仅选择5条记录?

DECLARE @Index INT;
DECLARE @PageSize INT;

SET @Index = 3;
SET @PageSize = 5;

SELECT *  FROM
  (SELECT  ROW_NUMBER() OVER (ORDER BY EmpID asc) as MyRowNumber,*
  FROM Employee) tblEmployee
WHERE MyRowNumber BETWEEN ( ((@Index - 1) * @PageSize )+ 1) AND @Index*@PageSize 

Answers:


17

测试的替代方法可能是:

;WITH x AS (SELECT EmpID, k = ROW_NUMBER() OVER (ORDER BY EmpID) FROM dbo.Emp)
SELECT e.columns
FROM x INNER JOIN dbo.Emp AS e
ON x.EmpID = e.EmpID
WHERE x.k BETWEEN (((@Index - 1) * @PageSize) + 1) AND @Index * @PageSize
ORDER BY ...;

是的,您打了两次桌子,但是在CTE中,您扫描整个桌子时,您仅是抓住钥匙,而不是所有数据。但是您确实应该看一下这篇文章:

http://www.sqlservercentral.com/articles/T-SQL/66030/

以及后续讨论:

http://www.sqlservercentral.com/Forums/Topic672980-329-1.aspx

在SQL Server 2012中,您当然可以使用new OFFSET/ FETCH NEXT语法:

;WITH x AS 
(
  SELECT EmpID FROM dbo.Emp
    ORDER BY EmpID
    OFFSET  @PageSize * (@Index - 1) ROWS
    FETCH NEXT @PageSize ROWS ONLY
)
SELECT e.columns
FROM x INNER JOIN dbo.Emp AS e
ON x.EmpID = e.EmpID
ORDER BY ...; 

应该注意,尽管OFFSET / FETCH NEXT与CTE方法相比没有任何性能上的好处
Akash 2013年

2
@Akash您是否对此进行了全面测试?我观察到了一些计划差异,但是没有具体提及性能,因为我没有进行任何广泛的测试。即使性能相同,语法也不会那么麻烦。我在这里做博客吧:sqlblog.com/blogs/aaron_bertrand/archive/2010/11/10/...
阿龙贝特朗

1
啊,您是对的,两者之间存在性能差异。我读过这篇文章:blogs.technet.com/b/dataplatforminsider/archive/2011/11/01/…他没有提及任何区别,但是只是看到channel9.msdn.com/posts/SQL11UPD03-REC-02他在那里显示有很大的不同..(尽管在音频方面过分强调了性能差异)
Akash 2013年

2

尽管您可能不知道其背后的机制,但是您可以通过将查询的性能与以下各项进行比较来进行自我测试:选择* from Employee。

SQL Server的最新版本在优化方面做得很好,但是它可能取决于多个因素。

ROW_NUMBER函数的执行方式将由Order By子句决定。在您的示例中,大多数人会猜测EmpID是主键。

有些where子句是如此复杂和/或编码或索引不好,您最好只返回整个数据集(这种情况很少见并且可以修复)。使用BETWEEN存在问题。

在假定最好将所有行返回到应用程序并让它找出来之前,您应该努力优化查询。检查估计。询问查询分析器。测试一些替代方法。


2

我知道问题是关于row_number()的,但我想添加sql server 2012的一项新功能。在sql server 2012中,引入了新功能OFFSET Fetch,它比row_number()快得多。我用过它,它给我很好的结果,希望你们也能得到同样的经验。

我在http://blogfornet.com/2013/06/sql-server-2012-offset-use/上找到了一个示例

这很有用。希望它对实现新功能也有帮助。


-2

我不认为它会返回原始表中的所有行。SQL Server优化。否则,选择一百万个条目将花费大量时间。我目前正在使用它,它比选择所有行要快得多。因此,请确保不会获取所有行。但是,这可能比仅获取前五行要慢,这可能是由于订购所需的时间


-2
DECLARE @PageIndex int;
DECLARE @PageSize int;
SET @PageIndex = 4;
SET @PageSize = 5;
;With ranked AS   --- Or you can make it a view
(
   SELECT ROW_NUMBER() OVER(ORDER BY IdentityId) AS RowNum,  *
   FROM logeventnew
)
SELECT *   --Your fields here
FROM Ranked
WHERE RowNum BETWEEN ((@PageIndex - 1) * @PageSize + 1)
    AND (@PageIndex * @PageSize)
ORDER BY IdentityId

4
您能否扩大答案?问题是有关分页如何在SQL Server内部进行工作-即数据库引擎如何完成请求。不幸的是,到目前为止,您的答案还没有解决实际的问题。
布朗斯顿先生
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.