これは非常に基本的な質問のように思えるかもしれません。ただし、科学的手法のファンとして、私は仮説を立て、それをテストして自分が正しいかどうかを確認するのが好きです。この場合、sys.dm_exec_sessions
の出力、より具体的には、単一の列が「読み取り」をよりよく理解しようとしています。
SQL Server Books Onlineでは、これを簡潔に次のように指定しています。
このセッション中に、このセッションのリクエストによって実行された読み取りの数。 null可能ではありません。
これは、セッションの開始以降、このセッションによって発行された要求を満たすためにディスクから読み取られたpagesの数を示していると考えられます。これは私がテストしようと思った仮説です。
同じテーブルのlogical_reads
列は次のように定義されます。
セッションで実行された論理読み取りの数。 null可能ではありません。
SQL Serverの使用経験から、この列はディスクからとメモリ内の両方で読み取られたページの数を反映していると思います。つまり、ページの合計数everセッションが読み取ったページの場所に関係なく。同様の情報を提供する2つの別々の列があることの差別化要因、つまり価値命題seemは、ディスクから読み取られたページ(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データページであることを示しています。期待どおりに:
2番目のselectステートメントは、TestReads
テーブルのメモリに何もないことを確認します。
新しいセッションでは、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.
3番目のセッションで、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 */
reads
とsys.dm_exec_sessions
の両方でlogical_reads
show 少なくとも 5,000が表示されると思います。悲しいかな、reads
はゼロを示しています。 logical_reads
は、5,000の北の予想される読み取り数を示しています-私のテストでは5,020を示しています。
SQL Serverがsys_dm_os_buffer_descriptors
DMVにより、TestReads
テーブル全体をメモリに読み込むことを知っています。
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
テストリグを作成しているセッションで784のreads
が表示されます。ただし、他のすべてのセッションでは、reads
列にゼロが表示されます。
SQL Serverテストインスタンスを11.0.6020に更新しました。ただし、結果は同じです。
私の理解では、reads
は物理(ディスクから)のみであり、logical_reads
はバッファプール(メモリから)からのみであることを常に理解しています。データページが2ページと合計3ページしかない小さなテーブルで簡単なテストを行ったところ、2つの定義が確認できたようです。
おそらくあなたに悪い結果をもたらしていることの1つは、あなたがメモリをクリアしていないということです。テスト間で次のコマンドを実行して、ディスクから強制的にリロードする必要があります。
DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;
私のテストセットアップは次のとおりです。
CREATE TABLE dbo.ReadTest (Col1 CHAR(7500) DEFAULT (' '));
INSERT INTO dbo.ReadTest (Col1) VALUES (DEFAULT), (DEFAULT);
次に、以下を実行しました。
SELECT reads, logical_reads FROM sys.dm_exec_sessions WHERE session_id = @@SPID;
SELECT * FROM dbo.ReadTest;
(はい、DMVを実行しているのと同じセッションでテストしていましたが、reads
フィールドの結果を歪めませんでした。 logical_reads
フィールド。)
テストのために、DBCCコマンドを実行してから、2つのSELECTクエリを実行します。次に、reads
とlogical_reads
の両方のフィールドでジャンプが発生します。 SELECTクエリを再度実行すると、reads
がさらにジャンプする場合があります。
その後、2つのSELECTクエリを何度も実行し、logical_reads
が4ずつ増加する間、reads
は同じままです。
次に、DBCCの実行からやり直して、同じパターンを確認します。私はこれを何度も行い、報告された数値はすべてのテスト実行で一貫していた。
より詳しい情報:
SQL Server 2012、SP2-64ビット(11.0.5343)でもテストしています。
次のDBCCコマンドは、試行したが効果はありません。
DBCC FREESYSTEMCACHE('ALL');
DBCC FREEPROCCACHE;
DBCC FREESESSIONCACHE;
ほとんどの場合DBCC DROPCLEANBUFFERS
は機能しますが、それがまだバッファプールにあることがときどきあります。奇数。
私が:
DBCC DROPCLEANBUFFERS
:読み取りは24増加し、logical_readsは52増加します。SELECT [Col1] FROM dbo.ReadTest;
を再度実行します。読み取りは増えませんが、logical_readsは6増えます。DBCC DROPCLEANBUFFERS
の直後のように)。52の論理読み取りが計画の生成と結果を説明しているように見えます。これは、計画の生成が追加の46の論理読み取りを引き起こしたことを意味します。しかし、物理的な読み取りは再度行われませんが、物理的な読み取りも行う必要があったときと同じ52の論理的な読み取りであるため、logical_reads
には物理的なreads
が含まれていません。質問でそれが述べられていたか、暗示されていたかにかかわらず、私はこの点を明確にしています。
しかし、sys.dm_os_buffer_descriptors
内のテーブルのデータページの存在を使用して(少なくとも少し)スローオフすることに気付いた1つの動作:他のプロセスによってリロードされます。 DROPCLEANBUFFERSを実行してすぐに確認すると、それはなくなっているはずです。しかし、数分待つと再び表示されますが、今回はすべてのデータページがありません。私のテストでは、テーブルに1つのIAMページと4つのデータページがあります。 SELECT
を実行した後、5ページすべてがバッファプールにあります。ただし、他のプロセスによってリロードされる場合、それはIAMページと1つのデータページにすぎません。 SSMS IntelliSenseの可能性があると思いましたが、クエリタブでそのオブジェクト名への参照をすべて削除しても、まだリロードされます。