DataBase  /  SQL Server  /  レポート取得ガイド

PART 02 — DMV(動的管理ビュー)による取得とセクション定義

SQL Server の DMV(Dynamic Management View / Function)は、 Oracle AWR の主要セクションに対応する性能情報をリアルタイムに参照できます。 本記事では待機統計・SQL 統計・I/O・メモリ・ロック・ラッチの各カテゴリについて、 主要 DMV の列定義・意味・取得 T-SQL クエリを体系的に整理します。

1. DMV とは — 基本概念と注意点

DMV(Dynamic Management Views)と DMF(Dynamic Management Functions)は、 SQL Server インスタンスの内部状態・統計情報を SQL で参照するための システムオブジェクト群です。sys.dm_* という命名規則で識別できます。

⚠️ 累積値であることに注意
多くの DMV は SQL Server の起動時点から現在までの累積値を保持します。 Oracle AWR のような「スナップショット間の差分」を自動取得する機能はなく、 定期的に値を保存して差分計算するスクリプト(後述)か、Query Store が必要です。
DBCC SQLPERF('sys.dm_os_wait_stats', CLEAR) で手動リセットも可能ですが、 本番環境での実行は基本的に推奨されません。

参照には VIEW SERVER STATE 権限が必要です。

T-SQL — 権限付与
-- VIEW SERVER STATE 権限を付与
GRANT VIEW SERVER STATE TO [monitoring_user];
-- データベースレベル DMV には VIEW DATABASE STATE も必要
GRANT VIEW DATABASE STATE TO [monitoring_user];

2. 待機統計 — sys.dm_os_wait_stats

Oracle AWR の Top 5 Timed Events(待機イベント)セクションに相当します。 SQL Server で最もボトルネック特定に使われる DMV です。

主要列定義

列名説明Oracle 対応
wait_type nvarchar(60) 待機の種類(例: PAGEIOLATCH_SH, LCK_M_X, CXPACKET など) Wait Event Name
waiting_tasks_count bigint この待機タイプが発生した回数の累積 Waits
wait_time_ms bigint 合計待機時間(ミリ秒)。シグナル待機を含む Total Wait Time (s)
max_wait_time_ms bigint 1 回の最大待機時間(ミリ秒)
signal_wait_time_ms bigint リソース解放後、スレッドがスケジュールされるまでの待機時間の累積
💡 リソース待機時間 = wait_time_ms − signal_wait_time_ms
signal_wait_time_ms が wait_time_ms の大部分を占める場合は CPU プレッシャーのサインです。

Top 10 待機イベント取得クエリ

T-SQL
-- Top 10 待機イベント(AWR の Top 5 Timed Events 相当)
-- アイドル系待機を除外してボトルネック候補だけを抽出
SELECT TOP 10
    wait_type,
    waiting_tasks_count,
    wait_time_ms,
    wait_time_ms - signal_wait_time_ms  AS resource_wait_time_ms,
    signal_wait_time_ms,
    max_wait_time_ms,
    CAST(100.0 * wait_time_ms
         / SUM(wait_time_ms) OVER ()     AS DECIMAL(5,2)) AS pct_total
FROM sys.dm_os_wait_stats
WHERE wait_type NOT IN (
    -- アイドル系待機(調査対象外)
    'SLEEP_TASK','SLEEP_SYSTEMTASK','SLEEP_DBSTARTUP',
    'SLEEP_DBRECOVER','SLEEP_DBTASK','SLEEP_TEMPDBSTARTUP',
    'SERVER_IDLE_CHECK','DISPATCHER_QUEUE_SEMAPHORE',
    'BROKER_TO_FLUSH','BROKER_TASK_STOP','BROKER_EVENTHANDLER',
    'CHECKPOINT_QUEUE','DBMIRROR_EVENTS_QUEUE','SQLTRACE_BUFFER_FLUSH',
    'CLR_AUTO_EVENT','CLR_MANUAL_EVENT','DISPATCHER_QUEUE_SEMAPHORE',
    'FT_IFTS_SCHEDULER_IDLE_WAIT','XE_DISPATCHER_WAIT',
    'XE_TIMER_EVENT','WAIT_XTP_OFFLINE_CKPT_NEW_LOG',
    'HADR_WORK_QUEUE','HADR_FILESTREAM_IOMGR_IOCOMPLETION',
    'SP_SERVER_DIAGNOSTICS_SLEEP','SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
    'ONDEMAND_TASK_QUEUE','REQUEST_FOR_DEADLOCK_SEARCH',
    'RESOURCE_QUEUE','LAZYWRITER_SLEEP','LOGMGR_QUEUE',
    'DIRTY_PAGE_POLL','DBMIRROR_WORKER_QUEUE','DBMIRROR_EVENTS_QUEUE',
    'WAIT_XTP_ONLINE_CKPT_NEW_LOG','PREEMPTIVE_HADR_LEASE_MECHANISM'
)
ORDER BY wait_time_ms DESC;

主要待機タイプの意味

wait_type意味典型的な原因
PAGEIOLATCH_SH / EX データページの物理 I/O 待機 バッファプール不足・低速ストレージ
LCK_M_* ロック待機(LCK_M_X=排他ロック など) 長時間トランザクション・インデックス不足
CXPACKET / CXCONSUMER 並列クエリのスレッド同期待機 MAXDOP 設定・並列度コストしきい値の問題
WRITELOG トランザクションログの書き込み待機 ログデバイスの I/O 遅延・ログファイル配置
SOS_SCHEDULER_YIELD CPU スケジューラへの自発的な譲渡 CPU バウンド処理・長時間 CPU 使用クエリ
ASYNC_NETWORK_IO クライアントがデータを読み取るのを待機 クライアント処理の遅延・ネットワーク帯域
OLEDB リンクサーバーやフルテキスト検索の I/O 待機 リンクサーバー応答遅延
RESOURCE_SEMAPHORE クエリ実行用メモリ許可待機 メモリ不足・ソート・ハッシュ処理の多用

3. SQL 統計 — sys.dm_exec_query_stats

Oracle AWR の SQL Statistics(Top SQL by Elapsed Time / CPU / Logical Reads)セクションに相当します。 キャッシュされたプランの実行統計を保持します。

主要列定義

列名説明Oracle 対応
total_elapsed_time 合計経過時間(マイクロ秒)。累積実行時間の合計 Elapsed Time
total_worker_time 合計 CPU 時間(マイクロ秒) CPU Time
total_logical_reads 合計論理読み取り数 Buffer Gets
total_logical_writes 合計論理書き込み数(ダーティページ生成)
total_physical_reads 合計物理読み取り数 Disk Reads
execution_count 実行回数 Executions
plan_handle 実行プランのハンドル(sys.dm_exec_cached_plans と結合)

Top SQL 取得クエリ(経過時間順)

T-SQL
-- Top SQL by 平均経過時間(AWR の SQL ordered by Elapsed Time 相当)
SELECT TOP 20
    qs.execution_count,
    qs.total_elapsed_time / 1000          AS total_elapsed_ms,
    qs.total_elapsed_time / qs.execution_count / 1000
                                           AS avg_elapsed_ms,
    qs.total_worker_time / 1000           AS total_cpu_ms,
    qs.total_worker_time / qs.execution_count / 1000
                                           AS avg_cpu_ms,
    qs.total_logical_reads,
    qs.total_logical_reads / qs.execution_count
                                           AS avg_logical_reads,
    qs.total_physical_reads,
    qs.creation_time                       AS plan_cached_at,
    SUBSTRING(st.text, (qs.statement_start_offset/2) + 1,
        ((CASE qs.statement_end_offset
            WHEN -1 THEN DATALENGTH(st.text)
            ELSE qs.statement_end_offset
          END - qs.statement_start_offset)/2) + 1
    )                                      AS sql_text,
    qp.query_plan
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle)   st
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
ORDER BY qs.total_elapsed_time DESC;
プロシージャ統計は sys.dm_exec_procedure_stats を使用
ストアドプロシージャ全体の統計が必要な場合は sys.dm_exec_procedure_stats を参照します。 構造は dm_exec_query_stats と同様で、object_id 列でプロシージャを特定できます。

4. I/O 統計 — sys.dm_io_virtual_file_stats

Oracle AWR の I/O Stat by Function / Tablespace セクションに相当します。 データベースファイル(データファイル・ログファイル)ごとの I/O 統計を取得します。

主要列定義

列名説明Oracle 対応
num_of_reads 読み取りの完了回数(累積) Physical Reads
num_of_bytes_read 読み取りバイト数(累積)
io_stall_read_ms 読み取り I/O の合計待機時間(ミリ秒) Read Time (s)
num_of_writes 書き込みの完了回数(累積) Physical Writes
io_stall_write_ms 書き込み I/O の合計待機時間(ミリ秒) Write Time (s)
io_stall 読み取り+書き込みの合計 I/O 待機時間(ミリ秒)

ファイル別 I/O 統計取得クエリ

T-SQL
-- ファイル別 I/O 統計(AWR の I/O Stat by Tablespace 相当)
SELECT
    DB_NAME(vfs.database_id)          AS database_name,
    mf.physical_name,
    mf.type_desc                       AS file_type,
    vfs.num_of_reads,
    vfs.num_of_bytes_read / 1048576.0 AS read_mb,
    vfs.io_stall_read_ms,
    CASE vfs.num_of_reads
        WHEN 0 THEN 0
        ELSE vfs.io_stall_read_ms * 1.0 / vfs.num_of_reads
    END                                AS avg_read_latency_ms,
    vfs.num_of_writes,
    vfs.num_of_bytes_written / 1048576.0 AS write_mb,
    vfs.io_stall_write_ms,
    CASE vfs.num_of_writes
        WHEN 0 THEN 0
        ELSE vfs.io_stall_write_ms * 1.0 / vfs.num_of_writes
    END                                AS avg_write_latency_ms,
    vfs.io_stall
FROM sys.dm_io_virtual_file_stats(NULL, NULL) vfs
JOIN sys.master_files mf
    ON vfs.database_id = mf.database_id
    AND vfs.file_id    = mf.file_id
ORDER BY vfs.io_stall DESC;
💡 I/O レイテンシの目安
データファイル読み取り: 平均 20ms 以下 が目標。25ms 超は要注意、50ms 超は深刻。
ログファイル書き込み: 平均 5ms 以下 が目標。WRITELOG 待機が多い場合は合わせて確認。

5. メモリ統計 — sys.dm_os_memory_clerks / buffer_descriptors

Oracle AWR の SGA / PGA / Buffer Pool 統計セクションに相当します。 SQL Server はバッファプールを中心にメモリを管理しています。

sys.dm_os_buffer_descriptors — バッファプール

列名説明
database_id バッファプールを使用しているデータベース ID
page_type ページ種別(DATA_PAGE, INDEX_PAGE, TEXT_TREE_PAGE など)
is_modified ダーティページ(未フラッシュの変更済みページ)かどうか
T-SQL — DB 別バッファプール使用量
-- DB 別バッファプール使用量(AWR の SGA Buffer Cache 相当)
SELECT
    DB_NAME(database_id)               AS database_name,
    COUNT(*)        * 8 / 1024.0       AS buffer_pool_mb,
    SUM(CASE WHEN is_modified = 1 THEN 1 ELSE 0 END) * 8 / 1024.0
                                        AS dirty_pages_mb
FROM sys.dm_os_buffer_descriptors
WHERE database_id <> 32767   -- プリアロケートページを除外
GROUP BY database_id
ORDER BY buffer_pool_mb DESC;

sys.dm_os_memory_clerks — メモリコンポーネント

T-SQL — メモリコンポーネント別使用量
-- メモリコンポーネント別使用量(AWR の Memory Statistics 相当)
SELECT
    type,
    name,
    SUM(pages_kb) / 1024.0 AS used_mb
FROM sys.dm_os_memory_clerks
GROUP BY type, name
ORDER BY used_mb DESC;

6. ロック統計 — sys.dm_tran_locks / dm_os_waiting_tasks

Oracle AWR の Enqueue Statistics / Lock Statistics セクションに相当します。 現在保持中のロックと待機中のタスクをリアルタイムに確認できます。

sys.dm_tran_locks の主要列

列名説明
resource_type ロックリソース種別(DATABASE, OBJECT, PAGE, KEY, RID, EXTENT など)
request_mode ロックモード(S=共有, X=排他, U=更新, IS/IX/SIX=インテント)
request_status GRANT(取得済み)/ WAIT(待機中)/ CONVERT(変換待ち)
request_session_id ロックを要求しているセッション ID

ブロッキングチェーン取得クエリ

T-SQL — ブロッキングチェーン
-- ブロッキングチェーンとブロックされているクエリ一覧
SELECT
    wt.session_id          AS blocked_session,
    wt.blocking_session_id AS blocking_session,
    wt.wait_type,
    wt.wait_duration_ms,
    wt.resource_description,
    SUBSTRING(st.text, (r.statement_start_offset/2)+1,
        ((CASE r.statement_end_offset
            WHEN -1 THEN DATALENGTH(st.text)
            ELSE r.statement_end_offset
          END - r.statement_start_offset)/2)+1
    )                      AS blocked_sql
FROM sys.dm_os_waiting_tasks wt
JOIN sys.dm_exec_requests   r
    ON wt.session_id = r.session_id
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) st
WHERE wt.blocking_session_id IS NOT NULL
ORDER BY wt.wait_duration_ms DESC;

7. ラッチ統計 — sys.dm_os_latch_stats / spinlock_stats

Oracle AWR の Latch Statistics / Mutex Statistics セクションに相当します。

sys.dm_os_latch_stats の主要列

列名説明
latch_class ラッチクラス(ACCESS_METHODS_DATASET_PARENT, BUFFER など)
waiting_requests_count このラッチクラスで待機した回数の累積
wait_time_ms 合計ラッチ待機時間(ミリ秒)
max_wait_time_ms 1 回の最大ラッチ待機時間(ミリ秒)
T-SQL — Top ラッチ待機
-- Top 10 ラッチ待機(AWR の Latch Statistics 相当)
SELECT TOP 10
    latch_class,
    waiting_requests_count,
    wait_time_ms,
    max_wait_time_ms,
    CAST(100.0 * wait_time_ms
         / NULLIF(SUM(wait_time_ms) OVER (), 0) AS DECIMAL(5,2)) AS pct_total
FROM sys.dm_os_latch_stats
WHERE wait_time_ms > 0
ORDER BY wait_time_ms DESC;

8. スナップショット差分取得パターン

DMV は累積値のため、Oracle AWR のように「特定期間の差分」を取得するには 2 時点のスナップショットを撮って差分を計算する必要があります。

T-SQL — 待機統計の差分取得(AWR スナップショット相当)
-- ① スナップショット1(計測開始時)を一時テーブルに保存
SELECT wait_type, waiting_tasks_count, wait_time_ms, signal_wait_time_ms
INTO #wait_snap1
FROM sys.dm_os_wait_stats
WHERE wait_type NOT IN (
    'SLEEP_TASK','SLEEP_SYSTEMTASK','SERVER_IDLE_CHECK',
    'DISPATCHER_QUEUE_SEMAPHORE','LAZYWRITER_SLEEP','LOGMGR_QUEUE',
    'REQUEST_FOR_DEADLOCK_SEARCH','RESOURCE_QUEUE','XE_TIMER_EVENT',
    'XE_DISPATCHER_WAIT','WAIT_XTP_ONLINE_CKPT_NEW_LOG'
);

-- ② 計測期間待機(例: 30 分)
WAITFOR DELAY '00:30:00';

-- ③ スナップショット2(計測終了時)を取得して差分を計算
SELECT
    s2.wait_type,
    s2.waiting_tasks_count - s1.waiting_tasks_count AS tasks_delta,
    s2.wait_time_ms        - s1.wait_time_ms        AS wait_ms_delta,
    s2.signal_wait_time_ms - s1.signal_wait_time_ms AS signal_ms_delta,
    (s2.wait_time_ms - s1.wait_time_ms)
    - (s2.signal_wait_time_ms - s1.signal_wait_time_ms)  AS resource_ms_delta
FROM sys.dm_os_wait_stats s2
JOIN #wait_snap1 s1 ON s2.wait_type = s1.wait_type
WHERE (s2.wait_time_ms - s1.wait_time_ms) > 0
ORDER BY wait_ms_delta DESC;

DROP TABLE #wait_snap1;
定期収集には SQL Server Agent ジョブを使用
本番環境では SQL Server Agent ジョブで定期的にスナップショットを 専用テーブルに保存し、後から任意の時間帯の差分を分析できるよう設計すると運用が容易です。 Query Store はこの仕組みを自動的に提供します(次記事参照)。