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 権限が必要です。
-- 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 | リソース解放後、スレッドがスケジュールされるまでの待機時間の累積 | — |
signal_wait_time_ms が wait_time_ms の大部分を占める場合は CPU プレッシャーのサインです。
Top 10 待機イベント取得クエリ
-- 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 取得クエリ(経過時間順)
-- 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 を参照します。
構造は 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 統計取得クエリ
-- ファイル別 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;
データファイル読み取り: 平均 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 | ダーティページ(未フラッシュの変更済みページ)かどうか |
-- 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 — メモリコンポーネント
-- メモリコンポーネント別使用量(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 |
ブロッキングチェーン取得クエリ
-- ブロッキングチェーンとブロックされているクエリ一覧
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 回の最大ラッチ待機時間(ミリ秒) |
-- 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 時点のスナップショットを撮って差分を計算する必要があります。
-- ① スナップショット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 ジョブで定期的にスナップショットを 専用テーブルに保存し、後から任意の時間帯の差分を分析できるよう設計すると運用が容易です。 Query Store はこの仕組みを自動的に提供します(次記事参照)。