「昨夜の深夜2時にシステムが遅かった」という問い合わせを受けたとき、そのときのセッション・SQL・待機状況を後から調べる手段が AWR(Automatic Workload Repository)とASH(Active Session History)です。
AWR はインスタンス全体の統計スナップショットを定期的に取得し、ASH はアクティブセッションを1秒ごとにサンプリングして過去の状態を再現できます。どちらも Oracle Enterprise Edition の機能(Diagnostics Pack ライセンス必要)で、DBA_HIST_* ビュー群としてアクセスできます。
- AWR スナップショットの仕組みと管理(取得間隔・保存期間の変更)
- 手動でスナップショットを取得する方法(DBMS_WORKLOAD_REPOSITORY)
- AWR レポートの生成方法と主要セクションの読み方
- ASH(V$ACTIVE_SESSION_HISTORY・DBA_HIST_ACTIVE_SESS_HISTORY)で過去の問題を特定する
- ADDM(自動データベース診断モニター)の診断結果の確認方法
- DBA_HIST_SQLSTAT・DBA_HIST_SYSTEM_EVENT を使った SQL・待機の長期分析
AWR・ASH・ADDM の使用には Oracle Enterprise Edition に加えてDiagnostics Pack(Oracle Database Management Packs)のライセンスが必要です。ライセンスなしで DBA_HIST_* ビューにアクセスすることは契約違反になる場合があります。必ずライセンスを確認してから使用してください。
AWR の仕組みとスナップショット管理
MMON バックグラウンドプロセスが定期的に(デフォルト:60分ごと)統計情報を SYSAUX 表領域に書き出します。このひとかたまりのデータを スナップショット と呼び、デフォルトで 8日間(691,200秒)保存されます。
-- 取得間隔と保存期間を確認
SELECT
snap_interval, -- スナップショット取得間隔
retention, -- 保存期間
topnsql -- AWR に保存するトップSQL件数
FROM DBA_HIST_WR_CONTROL;
-- スナップショットの一覧と取得時刻を確認
SELECT
snap_id,
instance_number,
TO_CHAR(begin_interval_time, 'YYYY-MM-DD HH24:MI') AS begin_time,
TO_CHAR(end_interval_time, 'YYYY-MM-DD HH24:MI') AS end_time
FROM DBA_HIST_SNAPSHOT
ORDER BY snap_id DESC
FETCH FIRST 10 ROWS ONLY;
-- 取得間隔を 30分、保存期間を 14日に変更
BEGIN
DBMS_WORKLOAD_REPOSITORY.MODIFY_SNAPSHOT_SETTINGS(
retention => 14 * 24 * 60, -- 保存期間(分)= 14日
interval => 30, -- 取得間隔(分)= 30分
topnsql => 100 -- トップSQL保存件数(デフォルト30)
);
END;
/
-- 即座にスナップショットを手動取得する
BEGIN
DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT;
END;
/
-- または
EXEC DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT;
-- 古いスナップショットを手動削除する
BEGIN
DBMS_WORKLOAD_REPOSITORY.DROP_SNAPSHOT_RANGE(
low_snap_id => 100, -- 削除開始スナップショットID
high_snap_id => 150 -- 削除終了スナップショットID
);
END;
/
AWR レポートの生成と主要セクションの読み方
AWR レポートは2つのスナップショット間の差分統計をまとめたレポートです。SQL*Plus やスクリプトから生成できます。
-- SQL*Plus から対話式でレポートを生成(スナップショットIDを選択する)
@$ORACLE_HOME/rdbms/admin/awrrpt.sql
-- HTML 形式のレポートを直接生成する(snap_id を直接指定)
SELECT OUTPUT
FROM TABLE(
DBMS_WORKLOAD_REPOSITORY.AWR_REPORT_HTML(
l_dbid => (SELECT dbid FROM V$DATABASE),
l_inst_num => 1,
l_bid => 200, -- 開始スナップショットID(begin)
l_eid => 210 -- 終了スナップショットID(end)
)
);
AWR レポートの主要セクション
| セクション名 | 内容 | チューニングでの注目点 |
|---|---|---|
| DB Time | 期間中の総 DB 処理時間(CPU + 非アイドル待機) | DB Time が大きいほど負荷が高い |
| Top 10 Foreground Events by Total Wait Time | 待機時間が多い上位イベント(Idle 除く) | 最重要セクション。ボトルネックの待機イベントを特定する |
| SQL ordered by Elapsed Time | 実行時間の合計が多い SQL Top 50 | チューニング対象 SQL の優先度付けに使う |
| SQL ordered by Gets | バッファ読み込みが多い SQL | 論理 I/O が高い非効率 SQL の特定 |
| SQL ordered by Reads | 物理読み込みが多い SQL | フルスキャンなど I/O バウンドの SQL の特定 |
| Instance Efficiency | バッファキャッシュヒット率・ライブラリキャッシュヒット率など | 各ヒット率が 95%以上かを確認 |
| Load Profile | 期間あたりの SQL 実行数・ハードパース数・トランザクション数など | ハードパース数が多ければバインド変数の未使用が疑われる |
DBA_HIST_SQLSTAT で SQL の長期パフォーマンス推移を確認する
-- sql_id を指定して日次の平均実行時間を確認する
SELECT
TO_CHAR(sn.begin_interval_time, 'YYYY-MM-DD HH24') AS hour,
s.plan_hash_value,
s.executions_delta AS exec_count,
ROUND(s.elapsed_time_delta
/ NULLIF(s.executions_delta, 0) / 1000000, 2) AS avg_elapsed_sec,
ROUND(s.buffer_gets_delta
/ NULLIF(s.executions_delta, 0), 0) AS avg_gets
FROM DBA_HIST_SQLSTAT s
JOIN DBA_HIST_SNAPSHOT sn
ON s.snap_id = sn.snap_id AND s.instance_number = sn.instance_number
WHERE s.sql_id = 'abc123xyz' -- 確認したい sql_id を指定
AND sn.begin_interval_time >= SYSDATE - 7
ORDER BY sn.snap_id;
-- ある期間のトップ SQL(経過時間合計の Top 10)
SELECT
s.sql_id,
ROUND(SUM(s.elapsed_time_delta) / 1000000, 2) AS total_elapsed_sec,
SUM(s.executions_delta) AS total_execs,
ROUND(SUM(s.elapsed_time_delta)
/ NULLIF(SUM(s.executions_delta), 0) / 1000000, 4) AS avg_elapsed_sec,
MAX(SUBSTR(t.sql_text, 1, 60)) AS sql_preview
FROM DBA_HIST_SQLSTAT s
JOIN DBA_HIST_SNAPSHOT sn
ON s.snap_id = sn.snap_id AND s.instance_number = sn.instance_number
LEFT JOIN DBA_HIST_SQLTEXT t ON s.sql_id = t.sql_id
WHERE sn.begin_interval_time BETWEEN
TO_DATE('2024-04-01', 'YYYY-MM-DD') AND
TO_DATE('2024-04-02', 'YYYY-MM-DD')
AND s.executions_delta > 0
GROUP BY s.sql_id
ORDER BY total_elapsed_sec DESC
FETCH FIRST 10 ROWS ONLY;
ASH(Active Session History)で過去の問題を再現する
ASH は アクティブセッションを1秒ごとにサンプリングして記録します。インメモリの V$ACTIVE_SESSION_HISTORY(最近数十分)と、それを定期的に AWR に書き出した DBA_HIST_ACTIVE_SESS_HISTORY(最大8日間)があります。
「昨夜2時に遅かった」という時刻を指定して、そのときどのセッションが・何のSQLで・何を待っていたかを後から特定できます。
-- 指定した時刻帯(例: 昨夜2時台)に最も待機が多かったイベントを確認
SELECT
event,
wait_class,
COUNT(*) AS sample_count,
ROUND(COUNT(*) * 100.0
/ SUM(COUNT(*)) OVER (), 1) AS pct
FROM DBA_HIST_ACTIVE_SESS_HISTORY
WHERE sample_time BETWEEN
TO_TIMESTAMP('2024-04-01 02:00', 'YYYY-MM-DD HH24:MI') AND
TO_TIMESTAMP('2024-04-01 03:00', 'YYYY-MM-DD HH24:MI')
AND session_type = 'FOREGROUND' -- ユーザーセッションのみ
AND session_state = 'WAITING' -- 待機中のサンプルのみ
GROUP BY event, wait_class
ORDER BY sample_count DESC;
-- 同時刻帯でどの SQL が最も多くサンプリングされたか(= 最も処理時間を使ったか)
SELECT
ash.sql_id,
COUNT(*) AS samples,
MAX(SUBSTR(t.sql_text, 1, 70)) AS sql_preview
FROM DBA_HIST_ACTIVE_SESS_HISTORY ash
LEFT JOIN DBA_HIST_SQLTEXT t ON ash.sql_id = t.sql_id
WHERE ash.sample_time BETWEEN
TO_TIMESTAMP('2024-04-01 02:00', 'YYYY-MM-DD HH24:MI') AND
TO_TIMESTAMP('2024-04-01 03:00', 'YYYY-MM-DD HH24:MI')
AND ash.session_type = 'FOREGROUND'
GROUP BY ash.sql_id
ORDER BY samples DESC
FETCH FIRST 10 ROWS ONLY;
-- 直近 10 分間のトップ待機(インメモリの ASH)
SELECT
event,
COUNT(*) AS samples
FROM V$ACTIVE_SESSION_HISTORY
WHERE sample_time >= SYSDATE - 10/1440 -- 過去10分
AND session_type = 'FOREGROUND'
AND session_state = 'WAITING'
GROUP BY event
ORDER BY samples DESC
FETCH FIRST 10 ROWS ONLY;
-- 直近 10 分でアクティブだったユーザー・SQL を確認
SELECT
ash.user_id,
u.username,
ash.sql_id,
COUNT(*) AS samples
FROM V$ACTIVE_SESSION_HISTORY ash
JOIN DBA_USERS u ON ash.user_id = u.user_id
WHERE ash.sample_time >= SYSDATE - 10/1440
AND ash.session_type = 'FOREGROUND'
GROUP BY ash.user_id, u.username, ash.sql_id
ORDER BY samples DESC;
ADDM の自動診断結果を確認する
ADDM(Automatic Database Diagnostic Monitor)は AWR のスナップショットを分析してパフォーマンス問題を自動診断し、改善アクションを提案します。AWR スナップショットが取得されるたびに自動的に実行されます。
-- 最近の ADDM タスクの一覧
SELECT
task_name,
description,
created,
status
FROM DBA_ADVISOR_TASKS
WHERE advisor_name = 'ADDM'
ORDER BY created DESC
FETCH FIRST 5 ROWS ONLY;
-- 特定の ADDM タスクの診断結果(推奨事項)を確認
SELECT
f.type,
f.impact, -- ベネフィット推定(DB Time の削減率 %)
f.message
FROM DBA_ADVISOR_FINDINGS f
WHERE f.task_name = 'ADDM:12345678' -- DBA_ADVISOR_TASKS の task_name を指定
ORDER BY f.impact DESC;
-- 特定の ADDM 推奨事項(アクション)を確認
SELECT
r.rank,
r.benefit,
r.message
FROM DBA_ADVISOR_RECOMMENDATIONS r
WHERE r.task_name = 'ADDM:12345678'
ORDER BY r.benefit DESC;
よく使う分析パターン
障害発生前後のスナップショットを特定する
-- 障害発生時刻(例: 2024-04-01 02:30)を挟むスナップショットを特定
SELECT
snap_id,
TO_CHAR(begin_interval_time, 'YYYY-MM-DD HH24:MI') AS begin_time,
TO_CHAR(end_interval_time, 'YYYY-MM-DD HH24:MI') AS end_time
FROM DBA_HIST_SNAPSHOT
WHERE begin_interval_time BETWEEN
TO_DATE('2024-04-01 02:00', 'YYYY-MM-DD HH24:MI') AND
TO_DATE('2024-04-01 04:00', 'YYYY-MM-DD HH24:MI')
ORDER BY snap_id;
-- → 得られたスナップショットIDを使って AWR レポートを生成
AWR の保存領域(SYSAUX)を確認する
-- SYSAUX 内の AWR コンポーネントの使用量を確認
SELECT
occupant_name,
ROUND(space_usage_kbytes / 1024, 1) AS usage_mb
FROM V$SYSAUX_OCCUPANTS
WHERE occupant_name LIKE 'SM/%' -- SM/AWR, SM/ASH など
ORDER BY space_usage_kbytes DESC;
まとめ
- AWR スナップショット:デフォルト 60 分ごとに取得、8 日間保存。
DBMS_WORKLOAD_REPOSITORY.MODIFY_SNAPSHOT_SETTINGSで設定変更できる - AWR レポート:2スナップショット間の差分統計。Top 10 Foreground Events と SQL ordered by Elapsed Time が最重要セクション
- DBA_HIST_SQLSTAT:特定の SQL の実行統計の時系列変化を確認できる。プラン変更の検出にも使える
- ASH(DBA_HIST_ACTIVE_SESS_HISTORY):過去の特定時刻の待機状況・アクティブ SQL を後から再現できる。障害の事後分析に必須
- ADDM:AWR から自動的にパフォーマンス問題を診断して推奨事項を提示する。DBA_ADVISOR_FINDINGS で確認する
待機イベントの意味と対処法は 待機イベント(Wait Events)完全ガイドを参照してください。AWR の分析対象になった SQL のプランは DBMS_XPLAN完全ガイドで詳細確認できます。遅い SQL の V$SQL を使ったリアルタイム特定方法は 遅いSQLを特定する方法完全ガイドを参照してください。

