The*_*war 8 sql-server execution-plan database-internals sql-server-2016
考虑以下查询:
CREATE PROC dbo.GetPage @orderid AS INT = 0, -- anchor sort key
@pagesize AS BIGINT = 25
AS
SELECT
TOP (@pagesize) orderid, orderdate, custid, empid
FROM dbo.Orders WHERE orderid > @orderid ORDER BY orderid;
exec GetPage 25,25
Run Code Online (Sandbox Code Playgroud)
上述查询的 SET STATISTICS IO 返回:
(25 row(s) affected)
Table 'Orders'. Scan count 1, logical reads 87, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Run Code Online (Sandbox Code Playgroud)
Itzik Ben-Gan 在他的书中对上述内容的解释是这样的:
执行查询计划所涉及的 I/O 成本由以下组成:
- 查找索引的叶子:3 次读取(索引具有三个级别)。
- 25 行的范围扫描:0-1 次读取(数百行适合一页)。
- 用于优化查找的嵌套循环预取:9 次读取(通过使用跟踪标志 8744 禁用预取来衡量)
- 25 次键查找:75 次读取
现在我的问题是,由于嵌套循环对从 seek 返回的每一行执行一次键查找,所以应该查找读取为 25*3 :75,与键查找相同吗?
CREATE PROC dbo.GetPage @orderid AS INT = 0, -- anchor sort key
@pagesize AS BIGINT = 25
AS
SELECT
TOP (@pagesize) orderid, orderdate, custid, empid
FROM dbo.Orders WHERE orderid > @orderid ORDER BY orderid;
exec GetPage 25,25
Run Code Online (Sandbox Code Playgroud)
现在我的问题是,由于嵌套循环对从 seek 返回的每一行进行一次键查找,所以应该查找读取 25*3 :75 与键查找相同
如果问题是“搜索是否也需要 75 次读取?” 那么答案是否定的,原因是 Itzik 给出并在问题中引用:
寻找索引的叶子:3 次读取(索引有三级) 25 行的范围扫描:0-1 次读取(数百行适合一页)
寻找范围扫描起始位置的初始查找(在索引查找运算符中)需要 3 次读取。从那时起,存储引擎会记住扫描的当前位置,因此获取下一个 Index Seek 行需要零次或一次读取。如果下一行在同一页上,则读取为零;如果在下一页,请阅读。
行为的差异是混淆的常见来源,也是我不喜欢将逻辑读取作为性能指标的原因之一。