Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从这篇SQLServer文章中获取页面的有效方法_Sql_Sql Server_Sql Server 2008_Tsql - Fatal编程技术网

从这篇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