这似乎是一个非常基本的问题,确实应该如此。但是,作为科学方法的忠实拥护者,我喜欢创建一个假设,然后对其进行检验以查看我是否正确。在这种情况下,我试图更好地理解的输出sys.dm_exec_sessions
,更具体地说,是单列“读取”的输出。
SQL Server联机丛书相当干脆地将其指定为:
在此会话期间,由该会话中的请求执行的读取次数。不可为空。
一个人可能会认为这将指示自会话开始以来从磁盘读取的页数,以满足该会话发出的请求。这是我以为我会检验的假设。
该logical_reads
表中的列定义为:
在会话上执行的逻辑读取数。不可为空。
从使用SQL Server的经验来看,我相信此列反映了从磁盘和内存读取的页面数。换句话说,页面的总数曾经由会话,无论这些页面驻留阅读。具有两个提供相似信息的独立列的差异或价值主张似乎是,对于特定会话,人们可以理解从磁盘读取的页面reads
与从缓冲区高速缓存读取的页面的比率logical_reads
。
在测试平台上,我创建了一个新数据库,创建了一个表,该表具有已知数量的数据页,然后在新会话中读取该表。然后,我sys.dm_exec_sessions
查看了reads
和logical_reads
专栏对会议的看法。在这一点上,我对结果感到困惑。也许有人可以为我阐明这一点。
测试装备:
USE master;
IF EXISTS (SELECT 1
FROM sys.databases d
WHERE d.name = 'TestReads')
BEGIN
ALTER DATABASE TestReads SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE TestReads;
END
GO
CREATE DATABASE TestReads;
GO
ALTER DATABASE TestReads SET RECOVERY SIMPLE;
BACKUP DATABASE TestReads TO DISK = 'NUL:'; /* ensure we are in
simple recovery model */
GO
USE TestReads;
GO
/*
create a table with 2 rows per page, for easy math!
*/
CREATE TABLE dbo.TestReads
(
ID INT NOT NULL
CONSTRAINT PK_TestReads
PRIMARY KEY CLUSTERED
IDENTITY(1,1)
, SomeData CHAR(4000) NOT NULL
);
/*
insert 5000 pages of data
*/
INSERT INTO dbo.TestReads (SomeData)
SELECT TOP(10000) o1.name
FROM sys.objects o1
, sys.objects o2
, sys.objects o3
ORDER BY o1.object_id
, o2.object_id
, o3.object_id;
/*
Verify we have 5,000 pages of data, with 10,000 rows.
*/
SELECT o.name
, p.rows
, au.total_pages
, au.used_pages
, au.data_pages
FROM sys.partitions p
INNER JOIN sys.objects o ON p.object_id = o.object_id
INNER JOIN sys.allocation_units au
ON p.hobt_id = au.container_id
AND (au.type = 1 or au.type = 0)
WHERE p.index_id = 1
AND o.name = 'TestReads'
AND o.type = 'U';
/*
issue a checkpoint to ensure dirty pages are flushed to disk
*/
CHECKPOINT 30;
DBCC DROPCLEANBUFFERS;
DBCC FREESYSTEMCACHE ('ALL');
DBCC FREEPROCCACHE;
DBCC FREESESSIONCACHE;
GO
/*
ensure we have no data cached in memory for the TestReads database
*/
USE master;
ALTER DATABASE TestReads SET OFFLINE WITH ROLLBACK IMMEDIATE;
ALTER DATABASE TestReads SET ONLINE;
SELECT DatabaseName = d.name
, SchemaName = s.name
, ObjectName = o.name
, AllocatedMB = COUNT(1) * 8192E0 / 1048576
, PagesInMemory = COUNT(1)
FROM sys.dm_os_buffer_descriptors dobd
INNER JOIN sys.allocation_units au
ON dobd.allocation_unit_id = au.allocation_unit_id
INNER JOIN sys.partitions p
ON au.container_id = p.hobt_id
AND (au.type = 1 OR au.type = 0)
INNER JOIN sys.objects o ON p.object_id = o.object_id
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
INNER JOIN sys.databases d
ON dobd.database_id = d.database_id
WHERE d.name = 'TestReads'
AND o.name = 'TestReads'
AND o.type = 'U'
GROUP BY d.name
, s.name
, o.name;
上面的第一条select语句显示,实际上该表确实包含10,000行,总共5,025页,已使用的页5,020和5,000个数据页。就像人们期望的那样:
第二个选择语句确认TestReads
表的内存中没有任何内容。
在一个新的session中,我们执行以下查询,并注意session_id:
USE TestReads;
SET STATISTICS IO ON;
SELECT *
FROM dbo.TestReads;
正如人们期望的那样,这会将整个表从磁盘读取到内存中,如的输出所示SET STATISTICS IO ON
:
(10000 row(s) affected)
Table 'TestReads'. Scan count 1, logical reads 5020, physical reads 3,
read-ahead reads 4998, lob logical reads 0, lob physical reads 0, lob
read-ahead reads 0.
在第三部分中,我们检查sys.dm_exec_sessions
:
SELECT des.session_id
, des.reads
, des.logical_reads
FROM sys.dm_exec_sessions des
WHERE des.session_id = 57; /* session_id from the 2nd (previous) session */
我希望看到sys.dm_exec_sessions
演出至少 5000两个reads
和logical_reads
。las,我看到reads
显示为零。 logical_reads
确实显示预期读取次数在5,000以上-在我的测试中显示5,020:
我知道SQL Server TestReads
借助sys_dm_os_buffer_descriptors
DMV 将整个表读入内存:
USE TestReads;
GO
SELECT DatabaseName = d.name
, SchemaName = s.name
, ObjectName = o.name
, AllocatedMB = COUNT(1) * 8192E0 / 1048576
, PagesInMemory = COUNT(1)
FROM sys.dm_os_buffer_descriptors dobd
INNER JOIN sys.allocation_units au
ON dobd.allocation_unit_id = au.allocation_unit_id
INNER JOIN sys.partitions p
ON au.container_id = p.hobt_id
AND (au.type = 1 OR au.type = 0)
INNER JOIN sys.objects o ON p.object_id = o.object_id
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
INNER JOIN sys.databases d
ON dobd.database_id = d.database_id
WHERE d.name = 'TestReads'
AND o.name = 'TestReads'
AND o.type = 'U'
GROUP BY d.name
, s.name
, o.name;
我究竟做错了什么?
我正在为此测试使用SQL Server 2012 11.0.5343。
进一步的发现:
如果我运行以下命令:
SELECT des.session_id
, des.reads
, des.logical_reads
FROM sys.dm_exec_sessions des
我reads
在创建测试装备的会话中看到784个;但是,所有其他会话在该reads
列中均显示为零。
现在,我已经将SQL Server测试实例更新为11.0.6020。但是结果是一样的。
SET STATISTICS IO ON
在第二届会议上我从表中读取之前,有趣的是报告了3次物理读取和4998次预读。但是,sys.dm_exec_sessions
仍然无法在reads
专栏中反映出来。
STATISTICS IO
i.stack.imgur.com/XbHae.png
reads
字段的某些增量出现延迟。我怀疑它的工作原理与session_space_usage或任何显示每个会话的tempdb使用情况的DMV一样,直到“请求”完成后才会增加。
sys.dm_exec_requests
将给您几乎与set statistics io on
结果相同。