2013-01-17 139 views
2

我对SQL Server如何使用公用表表达式和ROW_NUMBER实现更少的读取和性能改进有点困惑。为什么在表达式中实现的表不得不执行普通查询必须执行的所有读取操作,以允许查询使用ROW_NUMBER进行排序?SQL Server中的服务器端分页

+0

你还有什么其他的解决方案? – Quassnoi

+0

本质上只是一个查询不使用rownumber –

回答

4

CTE没有(必然)“实现”。这并不是说它不可避免地将所有行复制到其他地方,并且将对该副本执行其他操作(尽管它可能表现得如此优化器决定它更好)。

如果我们把这个简单的查询:

SELECT * 
FROM (
     SELECT *, 
       ROW_NUMBER() OVER (ORDER BY id) rn 
     FROM mytable 
     ) q 
WHERE rn BETWEEN 101 AND 110 

,并期待在它的计划,我们会看到这样的事情:

|--Filter(WHERE:([Expr1003]>=(101) AND [Expr1003]<=(110))) 
     |--Top(TOP EXPRESSION:(CASE WHEN (110) IS NULL OR (110)<(0) THEN (0) ELSE (110) END)) 
      |--Sequence Project(DEFINE:([Expr1003]=row_number)) 
       |--Segment 
         |--Clustered Index Scan(OBJECT:([ee].[dbo].[mytable].[PK__mytable__3213E83F29C2D227]), ORDERED FORWARD) 

这里,记录会被扫描(在id顺序为表被聚集在id上),分配了ROW_NUMBER(这是Sequence Project所做的),并传递给TOP,当达到某个阈值时,它会暂停执行(110记录在我们的情况)。

那些110记录被传递到Filter其中仅通过与rn大于100

该查询中的记录本身仅扫描110记录:

SQL Server parse and compile time: 
    CPU time = 0 ms, elapsed time = 1 ms. 

(строк обработано: 10) 
Table 'mytable'. Scan count 1, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 

SQL Server Execution Times: 
    CPU time = 0 ms, elapsed time = 0 ms. 

在3页。

现在让我们来看看unpaginated查询:

SELECT * 
FROM mytable 
ORDER BY 
     id 

这是一个非常简单的:阅读一切从桌上吐了出来。

|--Clustered Index Scan(OBJECT:([ee].[dbo].[mytable].[PK__mytable__3213E83F29C2D227]), ORDERED FORWARD) 

但是,容易看起来并不容易。该表是相当大的,我们需要做很多的读返回所有记录:

SQL Server parse and compile time: 
    CPU time = 0 ms, elapsed time = 0 ms. 

(строк обработано: 1310720) 
Table 'mytable'. Scan count 1, logical reads 2765, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 

SQL Server Execution Times: 
    CPU time = 266 ms, elapsed time = 11690 ms. 

因此,概括地说,分页查询才知道何时停止。

+0

谢谢 - 非常清楚。 –

+0

查询是否按照计算字段排序时,情况仍然如此吗?例如在我们的案例中,我们有一组结果,这些结果是通过靠近某个位置排序的。为了正确排序和分页结果,似乎每个记录都必须进行评估。 –

+0

@MatthewEvans:如果你想按照接近排序,你需要使用空间索引。不幸的是,它们在SQL Server中不能很好地工作,所以最好使用自己的平铺算法。 – Quassnoi