web-dev-qa-db-ja.com

sys.dm_exec_sessionsの "reads"列は実際に何を示していますか?

これは非常に基本的な質問のように思えるかもしれません。ただし、科学的手法のファンとして、私は仮説を立て、それをテストして自分が正しいかどうかを確認するのが好きです。この場合、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データページであることを示しています。期待どおりに:

enter image description here

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 */

readssys.dm_exec_sessionsの両方でlogical_reads show 少なくとも 5,000が表示されると思います。悲しいかな、readsはゼロを示しています。 logical_readsは、5,000の北の予想される読み取り数を示しています-私のテストでは5,020を示しています。

enter image description here

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;

enter image description here

何が悪いのですか?

このテストには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に更新しました。ただし、結果は同じです。

10
Max Vernon

私の理解では、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クエリを実行します。次に、readslogical_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増えます。
  • クエリテキストにスペースを追加して再実行します。読み取りは増えませんが、logical_readsは52増加します(DBCC DROPCLEANBUFFERSの直後のように)。

52の論理読み取りが計画の生成と結果を説明しているように見えます。これは、計画の生成が追加の46の論理読み取りを引き起こしたことを意味します。しかし、物理的な読み取りは再度行われませんが、物理的な読み取りも行う必要があったときと同じ52の論理的な読み取りであるため、logical_readsには物理的なreadsが含まれていません。質問でそれが述べられていたか、暗示されていたかにかかわらず、私はこの点を明確にしています。

しかし、sys.dm_os_buffer_descriptors内のテーブルのデータページの存在を使用して(少なくとも少し)スローオフすることに気付いた1つの動作:他のプロセスによってリロードされます。 DROPCLEANBUFFERSを実行してすぐに確認すると、それはなくなっているはずです。しかし、数分待つと再び表示されますが、今回はすべてのデータページがありません。私のテストでは、テーブルに1つのIAMページと4つのデータページがあります。 SELECTを実行した後、5ページすべてがバッファプールにあります。ただし、他のプロセスによってリロードされる場合、それはIAMページと1つのデータページにすぎません。 SSMS IntelliSenseの可能性があると思いましたが、クエリタブでそのオブジェクト名への参照をすべて削除しても、まだリロードされます。

2
Solomon Rutzky