STATISTICS IO 输出是否包括版本存储读取?

For*_*est 9 sql-server tempdb-version-store

SQL Server 有一个选项SET STATISTICS IO ON可以显示查询的逻辑和物理页读取次数。这些统计信息是否包括 SNAPSHOT 和 RCSI 查询的版本存储读取?

For*_*est 10

STATISTICS IO 不包括版本存储读取,至少对于 tempdb 中的版本存储。

这是证明的演示:

--setup script
USE master
GO

CREATE DATABASE TestDB
GO

ALTER DATABASE TestDB
SET ALLOW_SNAPSHOT_ISOLATION ON
GO

USE TestDB
GO

DROP TABLE IF EXISTS dbo.Test
GO

CREATE TABLE dbo.Test (ID int identity PRIMARY KEY, junk int)

INSERT dbo.Test
SELECT TOP (100000) 1
FROM master.dbo.spt_values a
CROSS JOIN master.dbo.spt_values b
Run Code Online (Sandbox Code Playgroud)

在一个 SSMS 选项卡中启动 30 秒的更新循环

--UPDATE loop
SET NOCOUNT ON
DECLARE @stop datetime = DATEADD(SECOND, 30, GETDATE())

WHILE GETDATE() < @stop
BEGIN
    BEGIN TRAN

    UPDATE dbo.Test
    SET junk += 1

    COMMIT
END

UPDATE dbo.Test
SET junk = 1
Run Code Online (Sandbox Code Playgroud)

在循环进行时,在SNAPSHOTwith 中运行两个相同的查询STATISTICS IO ON,间隔 15 秒以允许版本累积。

USE TestDB
SET STATISTICS IO ON
GO

SET TRANSACTION ISOLATION LEVEL SNAPSHOT

BEGIN TRAN

SELECT MAX(junk)
FROM dbo.Test

WAITFOR DELAY '00:00:15'

SELECT MAX(junk)
FROM dbo.Test

COMMIT
Run Code Online (Sandbox Code Playgroud)

IO 统计数据显示相同的读取: 统计 IO

但实际执行计划显示,由于读取版本存储,第二个查询的扫描花费了更多时间。 实际计划

为了向自己证明这个查询导致了 tempdb 读取,您可以使用这个扩展事件会话(这显然比 Profiler 更好),过滤到运行读取查询的会话:

CREATE EVENT SESSION [file_reads] ON SERVER 
ADD EVENT sqlserver.file_read_completed(
    ACTION(sqlserver.session_id,sqlserver.sql_text)
    WHERE ([sqlserver].[session_id]=(52)))
ADD TARGET package0.event_file(SET filename=N'file_reads')
GO
Run Code Online (Sandbox Code Playgroud)

在演示期间查看该 XE 会话的“实时数据”,您可以看到针对数据库 id 2 (tempdb) 的读取,它也捕获了我们读取查询的查询文本:

显示 tempdb 读取的 XE 会话屏幕截图

特别感谢 Paul White 向 STATISTICS IO 提出这个问题。