从这篇SQLServer文章中获取页面的有效方法
我正在阅读关于如何高效地在大型数据集中分页的文章,因为我不喜欢从这篇SQLServer文章中获取页面的有效方法,sql,sql-server,sql-server-2008,tsql,Sql,Sql Server,Sql Server 2008,Tsql,我正在阅读关于如何高效地在大型数据集中分页的文章,因为我不喜欢行数,而获取是最糟糕的 这是一篇文章: 现在,本文有一段代码: CREATE PROCEDURE [dbo].[usp_PageResults_NAI] ( @startRowIndex int, @maximumRows int ) AS DECLARE @first_id int, @startRow int -- A check can be added to make sure @startRowIn
行数
,而获取
是最糟糕的
这是一篇文章:
现在,本文有一段代码:
CREATE PROCEDURE [dbo].[usp_PageResults_NAI]
(
@startRowIndex int,
@maximumRows int
)
AS
DECLARE @first_id int, @startRow int
-- A check can be added to make sure @startRowIndex isn't > count(1)
-- from employees before doing any actual work unless it is guaranteed
-- the caller won't do that
-- Get the first employeeID for our page of records
SET ROWCOUNT @startRowIndex
SELECT @first_id = employeeID FROM employees ORDER BY employeeid
-- Now, set the row count to MaximumRows and get
-- all records >= @first_id
SET ROWCOUNT @maximumRows
SELECT e.*, d.name as DepartmentName
FROM employees e
INNER JOIN Departments D ON
e.DepartmentID = d.DepartmentID
WHERE employeeid >= @first_id
ORDER BY e.EmployeeID
SET ROWCOUNT 0
GO
此演示代码看起来不错(与您看到的其他演示一样:))。上述代码之所以有效,是因为他在中使用了orderbyemployeeid
从employeeorderbyemployeeid
中选择@first\u id=employeeid
假设我有一个名为FirstName
的字段,并希望按该字段排序。那么如何编写上述过程?上述过程显然不起作用,因为这样我们就无法编写WHERE employeeid>=@first\u id
,因为如果我们按名称订购,我们就无法获得first\u id
。这是因为其中
是在订购人
之前执行的
如果我们将上述查询更改为:
Select * From (SELECT e.*, d.name as DepartmentName
FROM employees e
INNER JOIN Departments D ON
e.DepartmentID = d.DepartmentID
ORDER BY e.EmployeeID) v WHERE employeeid >= @first_id
然后它就可以工作了,但这意味着,上面的查询在较大的数据集上的性能会非常差
那么,我们如何将上述演示代码用于生产使用呢?感谢您的帮助。您的问题似乎是希望使用另一种方法,因为在大型数据集中对非唯一字段进行排序时,
行数
不起作用。但是,问题是,在对大型数据集中的非唯一字段进行排序时,您想要使用的方法无法很好地工作,因此您可以如何纠正这一问题
答案是,在非唯一字段上对大型数据集进行排序不会很好地执行,除非您很好地使用索引
为了证明ROW\u NUMBER
比您给出的方法更好,即使是在主键排序的简单情况下,我从您的链接创建了模式,并添加了以下过程:
CREATE PROCEDURE dbo.usp_PagedResults_RowNumber
(
@startRowIndex int,
@maximumRows int
)
AS
WITH Emp AS
( SELECT e.*, rn = ROW_NUMBER() OVER(ORDER BY e.EmployeeID)
FROM employees e
)
SELECT TOP (@MaximumRows)
EmployeeID,
LastName,
FirstName,
e.DepartmentID,
Salary,
HireDate,
d.Name AS DepartmentName
FROM Emp e
INNER JOIN Departments D ON
e.DepartmentID = d.DepartmentID
WHERE rn >= @startRowIndex
ORDER BY EmployeeID;
然后我比较了两个问题:
EXECUTE usp_PageResults_NAI 4500, 20;
EXECUTE usp_PagedResults_RowNumber 4500, 20;
首先查看IO统计数据,您发布的过程如下:
Table 'Employees'. Scan count 1, logical reads 48
(1 row(s) affected)
(20 row(s) affected)
Table 'Departments'. Scan count 1, logical reads 41
Table 'Employees'. Scan count 1, logical reads 2
(1 row(s) affected)
所有统计数据以物理读取0、预读读取0、lob逻辑读取0、lob物理读取0、lob预读读取0结束。
因此,为了可读性,我从所有统计数据中删除了此项
使用ROW_NUMBER()时的统计信息:
这两者之间并没有太多的区别,但行数稍微好一些,只需少一次索引扫描和两次逻辑读取
接下来看一下执行计划。使用Rowcount的成本估计为查询成本的84%:
排在第二位的人数只有区区16%
就实际执行时间而言,考虑到数据的大小,我无法得出合理的结论,因为两者都执行得很快。我只能假设更简单的计划,更低的IO也会使行数更快
因此,与其试图将一个正方形的木钉塞进一个圆孔中,并使用这种行计数方法在字段(如FirstName)上翻页,不如在FirstName上创建一个索引,以便在进行排序时辅助行数。e、 g
CREATE NONCLUSTERED INDEX IX_Employees_FirstName ON dbo.Employees (FirstName ASC) INCLUDE (DepartmentID);
为了说明差异,我运行了以下查询:
SELECT EmployeeID,
DepartmentID,
RowNumber = ROW_NUMBER() OVER(ORDER BY FirstName, EmployeeID)
FROM Employees;
在添加索引之前,请执行以下操作:
之前
Table 'Employees'. Scan count 1, logical reads 501
之后
Table 'Employees'. Scan count 1, logical reads 249
这表明排序能够使用索引将逻辑读取的数量减半。我尝试了多种不同的SP分页方式,但没有任何效果。部分原因是在我的例子中,如果我使用所有的条件、条件、排序、筛选等,SP非常复杂,运行速度很慢,因此我无法在每次新页面请求中重复所有这些条件 我实现它的方式—我确实使用所有的条件、条件、排序、筛选等运行它,但我只这样运行一次—并检索所有的行,但不是获取所有的列,而是只检索主键(顺便说一句,与所有列重新检索相比,主键加快了运行速度) 在.NET代码中,我将该列表存储在
通用列表(整数)
中。每次用户请求一个新页面时,我都会将一个ID列表(比如每次50个)传递给SP。SP,而不是对条件、排序、筛选等执行完全搜索。simple会内部连接到该列表
这种方法被证明是非常有效的,因为所有的条件——包括记录的顺序——都已保存在ID列表中。它也很灵活,在任何时候我都可以通过一次提供不同数量的ID轻松更改“每页行数”。部门是否有PK(或唯一)。部门ID?@Roman:这些不是我的表格。这是问题中所述的演示代码。如果它们不是您的表格,那么您为什么会问“那么,我们如何将上述演示代码用于生产使用?”建议更改的目的是什么?它不按名字排序。@Blam的可能重复:上面的“演示代码”指的是演示代码中使用的逻辑,而不是整个代码。如果搜索返回100万行,你会全部下载吗?如果达到6400万,您将达到.NET 1 GB的限制。@BARM您能详细说明一下计算方法吗?然后在达到对象大小限制之前,告诉您可以在.NET中缓存多少。告诉我下载一百万到cache.NET列表需要多长时间。你甚至没有回答如何排序的问题。@bum即使我使用了64位ID(我没有),64位也会产生8个字节。对于小于8Mb的100万条记录来说,这是一个很小的代价,可以在几乎没有额外内存成本的情况下快速随机访问1M数据集中的任何页面。哦,如果你对我的帖子多加注意的话,ID列表已经按照初始请求进行了排序,所以列表已经排序了。它没有回答如何创建排序列表的问题。你是否回答了在达到1GB.NET限制之前有多大的问题?-没有,你回答了下载一百万需要多长时间?-没有,答案不可缩放。我接受了你的答案,因为我最初的问题本身没有答案。虽然这不是我问题的答案,因为我已经读过了
Table 'Employees'. Scan count 1, logical reads 249