聚集索引数据访问

use*_*729 3 sql-server sql-server-2019

我试图了解 SQL Server 如何从聚集索引访问数据。我的理解是,当表具有聚集索引时,SQL 应该能够使用搜索谓词搜索保存记录的单页。

但是,我的测试向我展示了执行查询时它会加载更多数据页。

设置

CREATE TABLE t2(id INT IDENTITY PRIMARY KEY CLUSTERED,col2 VARCHAR(500),col3 VARCHAR(500));

INSERT INTO [dbo].[t2]([col2],[col3])
SELECT TOP 10010 REPLICATE('z',490),REPLICATE('*',490)
FROM sys.all_columns c1,
     sys.all_columns c2
Run Code Online (Sandbox Code Playgroud)

以下查询

select *
from sys.dm_db_index_physical_stats(db_id(),object_id(N'dbo.t2'),DEFAULT,null,'DETAILED');
Run Code Online (Sandbox Code Playgroud)

将输出显示为

在此处输入图片说明

然后我清除了缓存

CHECKPOINT 

GO

DBCC DROPCLEANBUFFERS
Run Code Online (Sandbox Code Playgroud)

并将以下SELECT搜索运行到一行中

SELECT  [fplc].*,[t2].[col3] FROM [dbo].[t2] AS [t2] 
CROSS APPLY sys.[fn_PhysLocCracker](%%physloc%%) AS [fplc]
WHERE id=4582
Run Code Online (Sandbox Code Playgroud)

上面的查询告诉我记录位于第 1061 页

我使用下面的代码检查有多少页已加载到缓冲区中以获取我的 SELECT 结果

SELECT buffers.* FROM sys.dm_os_buffer_descriptors  buffers
INNER JOIN sys.allocation_units AS au
    ON au.[allocation_unit_id] = buffers.[allocation_unit_id]
INNER JOIN sys.partitions AS p
    ON au.[container_id] = p.[partition_id]
INNER JOIN sys.indexes AS i
    ON i.[index_id] = p.[index_id] AND p.[object_id] = i.[object_id]
WHERE p.[object_id] > 100
and [database_id] = DB_ID () AND i.[object_id]=OBJECT_ID('t2')
 ORDER BY [page_level] desc
Run Code Online (Sandbox Code Playgroud)

为什么 SQL 加载所有标记为绿色的页面?页面是否由 READ AHEAD 加载? 在此处输入图片说明

Mar*_*ith 5

这在The Read Ahead 中解释,这不算作 Read Ahead

我想在这篇文章中讨论的是另一种预取机制,当 SQL 运行任何被视为企业版的版本(即开发人员、评估和企业本身)时,任何查询都可以触发该机制。此优化的目的是尽快预热缓存。为此,缓冲池将从磁盘读取单个页面的任何请求转换为将读取包含最初请求的页面的整个范围的请求。

在您的情况下,您在使用DBCC DROPCLEANBUFFERS. 所以 SQL Server 处于它会尝试快速预热缓存的状态。

您需要阅读三页来执行查找(索引的每一级各一页)。这些是页面111113821061

所以,你最终将与页码3个的整个范围1056 - 10631104 - 11111376 - 1383

如果您对报价中提到的其他 SKU 进行相同的实验(并且未启用跟踪标志 840),您应该会看到预期的三个页面(以下针对 Express LocalDB)

在此处输入图片说明