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 页。
现在让我们看看未分页的查询:
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.
所以,简而言之,分页查询只知道何时停止。