Oracle の SQL Trace は、セッションまたはシステム全体の SQL 実行統計と待機イベントをテキストファイルに記録する診断機能です。取得したトレースファイルを tkprof で整形することで、どの SQL が遅いのか・なぜ遅いのかをパース回数・実行計画・待機イベントの観点で分析できます。
EXPLAIN PLAN や DBMS_XPLAN は単発の実行計画を確認する用途ですが、SQL Trace はアプリケーションが実際に発行した SQL すべての統計を時系列で記録するため、本番環境のボトルネック調査や N+1 問題の発見に特に威力を発揮します。
この記事でわかること
- SQL Trace の有効化方法(ALTER SESSION・DBMS_SESSION・DBMS_MONITOR)
- 10046 トレースのレベル(level 4/8/12)と取得できる情報の違い
- トレースファイルの場所の確認方法(V$DIAG_INFO・USER_DUMP_DEST)
- tkprof でトレースファイルを整形して解析する方法
- tkprof 出力の読み方(PARSE/EXECUTE/FETCH・Elapsed・CPU・WAIT)
- DBMS_MONITOR でサービス・モジュール単位にトレースを取得する方法
SQL Trace の有効化方法
SQL Trace を有効にする方法は主に3つあります。
| 方法 | 対象 | 特徴 |
|---|---|---|
ALTER SESSION SET SQL_TRACE = TRUE |
現在のセッション | 最もシンプル。自分のセッションのみ |
ALTER SESSION SET EVENTS '10046 ...' |
現在のセッション | レベル指定で待機イベントも記録できる |
DBMS_MONITOR |
別セッション・サービス・モジュール | DBA 権限で他セッションや条件指定のトレースが可能 |
ALTER SESSION でトレースを有効にする
-- 方法①: 基本的な SQL Trace(統計のみ) ALTER SESSION SET SQL_TRACE = TRUE; -- ここで対象の SQL を実行する SELECT COUNT(*) FROM employees WHERE department_id = 60; -- ...アプリケーションを操作する... -- トレースを終了する ALTER SESSION SET SQL_TRACE = FALSE; -- 方法②: 10046イベント(レベル指定あり) -- level 1: SQL Trace 相当(統計のみ) -- level 4: バインド変数の値も記録する -- level 8: 待機イベントも記録する -- level 12: バインド変数 + 待機イベントの両方(最も詳細) ALTER SESSION SET EVENTS '10046 trace name context forever, level 12'; -- トレースを終了する ALTER SESSION SET EVENTS '10046 trace name context off'; -- トレースファイルに識別子を付ける(後で検索しやすくなる) ALTER SESSION SET TRACEFILE_IDENTIFIER = 'my_diagnosis'; -- → トレースファイル名に 'my_diagnosis' が含まれるようになる
level 12 を推奨する理由
待機イベント(level 8)を含めることで、遅い SQL の原因が「CPU の処理量が多い」のか「I/O やロックで待っている」のかを区別できます。バインド変数値(level 4)を含めると、実際に使われた値でのボトルネック分析が可能になります。調査目的では level 12 を指定するのがベストプラクティスです。
トレースファイルの場所を確認する
トレースファイルのディレクトリと名前を確認する
-- Oracle 11g 以降(Automatic Diagnostic Repository を使う環境)
-- V$DIAG_INFO でトレースファイルの場所を確認する
SELECT name, value FROM V$DIAG_INFO
WHERE name IN ('Diag Trace', 'Default Trace File');
-- Diag Trace: トレースファイルが格納されるディレクトリ
-- Default Trace File: 現在のセッションのトレースファイルのフルパス
-- 現在のセッションの SID・プロセス番号からファイル名を特定する
SELECT
s.sid,
s.serial#,
p.spid AS os_pid, -- OS プロセス ID(ファイル名に使われる)
s.username,
s.tracefile -- 11g 以降は V$SESSION に tracefile 列がある
FROM V$SESSION s
JOIN V$PROCESS p ON s.paddr = p.addr
WHERE s.audsid = SYS_CONTEXT('USERENV', 'SESSIONID');
-- Oracle 10g 以前(USER_DUMP_DEST を使う)
SHOW PARAMETER user_dump_dest;
-- トレースファイル名のパターン: <SID>_ora_<SPID>.trc
-- 例: orcl_ora_12345.trc
別セッションや条件指定でトレースを取得する
DBMS_MONITOR でトレースを有効にする
-- 別セッション(SID + SERIAL#)のトレースを有効にする(DBA権限が必要)
-- 対象セッションの SID と SERIAL# を確認する
SELECT sid, serial#, username, status FROM V$SESSION WHERE username = 'APP_USER';
EXEC DBMS_MONITOR.SESSION_TRACE_ENABLE(
session_id => 42, -- SID
serial_num => 1234, -- SERIAL#
waits => TRUE, -- 待機イベントを記録する
binds => TRUE -- バインド変数の値を記録する
);
-- 対象セッションのトレースを終了する
EXEC DBMS_MONITOR.SESSION_TRACE_DISABLE(
session_id => 42,
serial_num => 1234
);
-- サービス名 + モジュール名 + アクション名の組み合わせでトレースを有効にする
-- アプリケーションが DBMS_APPLICATION_INFO でモジュール名を設定している場合に使う
EXEC DBMS_MONITOR.SERV_MOD_ACT_TRACE_ENABLE(
service_name => 'ORCL',
module_name => 'OrderProcess', -- DBMS_APPLICATION_INFO.SET_MODULE で設定した名前
action_name => DBMS_MONITOR.ALL_ACTIONS, -- NULL ですべてのアクション
waits => TRUE,
binds => FALSE
);
EXEC DBMS_MONITOR.SERV_MOD_ACT_TRACE_DISABLE(
service_name => 'ORCL',
module_name => 'OrderProcess',
action_name => DBMS_MONITOR.ALL_ACTIONS
);
-- 現在のセッションから DBMS_SESSION でトレースを有効にする
EXEC DBMS_SESSION.SET_SQL_TRACE(sql_trace => TRUE);
EXEC DBMS_SESSION.SET_SQL_TRACE(sql_trace => FALSE);
tkprof でトレースファイルを解析する
取得したトレースファイル(.trc)を人間が読みやすい形式に整形するのがtkprof(Trace Kernel Profiler)コマンドです。OS コマンドラインから実行します。
tkprof コマンドの基本的な使い方
# 基本構文: tkprof <トレースファイル> <出力ファイル> [オプション] tkprof orcl_ora_12345.trc output.txt # sort オプション: ボトルネック SQL を先に表示する # sort=fchela: 経過時間(elapsed)の降順で並べる → 遅い SQL を先に見られる # sort=prsela: PARSE の経過時間の降順 # sort=exeela: EXECUTE の経過時間の降順 tkprof orcl_ora_12345.trc output.txt sort=fchela # sys=no: SYS(内部処理)の SQL を除外して見やすくする tkprof orcl_ora_12345.trc output.txt sort=fchela sys=no # explain オプション: EXPLAIN PLAN を取得して実行計画を出力に含める tkprof orcl_ora_12345.trc output.txt sort=fchela sys=no explain=username/password@ORCL # aggregate=yes(デフォルト): 同一 SQL の統計を集計する # aggregate=no: 実行のたびに別々に記録する tkprof orcl_ora_12345.trc output.txt sort=fchela sys=no aggregate=no # Oracle 12c 以降: adrci コマンドでトレースファイルを確認する # adrci> show tracefile # adrci> show trace <tracefilename>
tkprof 出力の読み方
tkprof が生成するテキストファイルの各項目の意味を理解することが分析の核心です。
tkprof 出力の例と各項目の意味
# tkprof 出力の典型的なフォーマット(抜粋) SELECT e.employee_id, e.last_name, d.department_name FROM employees e JOIN departments d ON e.department_id = d.department_id WHERE e.salary > :1 call count cpu elapsed disk query current rows -------- ------ -------- ---------- -------- ---------- ---------- ---------- Parse 1 0.01 0.02 0 0 0 0 Execute 100 0.05 0.10 0 0 0 0 Fetch 100 2.30 5.80 200 50000 0 2000 -------- ------ -------- ---------- -------- ---------- ---------- ---------- total 201 2.36 5.92 200 50000 0 2000 Misses in library cache during parse: 1 ← ハードパース発生 Optimizer mode: ALL_ROWS Parsing user id: 42 (APP_USER) # ----------------------------------------------- # 各列の意味: # count : 操作の実行回数(Fetch が多い → N+1 問題の可能性) # cpu : CPU 使用時間(秒) # elapsed : 実際の経過時間(秒)。cpu より大きい場合は待機が多い # disk : 物理読み取りブロック数(多い → テーブルフルスキャンや I/O ボトルネック) # query : 一貫性読み取りブロック数(論理読み取り) # current : カレントモード読み取りブロック数(DML で多い) # rows : 処理した行数 # ポイントの見方: # ① elapsed >> cpu → 待機イベント(I/O・ロック)が原因で遅い # ② Parse count が多い → バインド変数不使用によるハードパースが多発している # ③ disk が多い → 物理 I/O が多い。インデックスが効いていない可能性 # ④ Fetch count が Execute count の数倍 → ArraySize が小さい・N+1 問題 # ⑤ "Misses in library cache during parse: N" → ハードパースが N 回発生
tkprof 出力の待機イベントセクション(level 8/12 時)
-- level 8 または 12 でトレースを取得した場合、以下のような待機イベント情報が出力される -- Elapsed times include waiting on following events: -- Event waited on Times Max. Wait Total Waited -- ------------------------------------------- ---------- ------------ -- db file sequential read 150 0.05 1.20 -- db file scattered read 20 0.30 2.10 -- latch: cache buffers chains 5 0.01 0.02 -- enq: TX - row lock contention 2 3.00 5.50 -- db file sequential read: インデックス読み取りの単一ブロック I/O -- db file scattered read : フルスキャンの複数ブロック I/O(多い場合は全件スキャン疑い) -- latch: 内部競合(通常は少ない) -- enq: TX - row lock contention: 行ロック競合(長時間の場合は接続先セッションのロック調査が必要) -- → 待機の合計が elapsed に近い場合は CPU でなく待機が主因
tkprof で発見できるよくある問題パターン
| 症状(tkprof で見える数値) | 推定原因 | 対処法 |
|---|---|---|
| Parse count が Execute count と同じ・多い | バインド変数未使用のハードパース | バインド変数を使う。CURSOR_SHARING を検討 |
| disk(物理読み取り)が多い | フルテーブルスキャン・インデックス未使用 | インデックス追加・EXPLAIN PLAN で実行計画を確認 |
| Fetch count が行数の数倍 | ArraySize が小さい・1行ずつ FETCH している | JDBC fetchSize・OCI arraysize を増やす |
| elapsed >> cpu(待機が大半) | I/O 待機・ロック待機 | 待機イベントを確認。ロックなら V$SESSION_WAIT でブロッカーを特定 |
| 同一 SQL が大量に実行されている | N+1 問題・ループ内の SQL | JOIN や一括取得に変更する |
トレース有効状態の確認と管理
現在のトレース状態と設定を確認する
-- 現在セッションで SQL Trace が有効かどうかを確認する SELECT value FROM V$PARAMETER WHERE name = 'sql_trace'; -- FALSE: システムレベルは無効(ALTER SESSION で個別に有効にしている場合は別) -- 現在有効なモニタリング設定を確認する(DBMS_MONITOR で設定したもの) SELECT * FROM DBA_ENABLED_TRACES; -- TYPE: SESSION / SERVICE / SERVICE_MODULE / SERVICE_MODULE_ACTION -- WAITS: YES/NO -- BINDS: YES/NO -- システム全体で SQL Trace を有効にする(重大なパフォーマンス影響があるため注意) ALTER SYSTEM SET SQL_TRACE = TRUE; -- 本番環境では使用しない ALTER SYSTEM SET SQL_TRACE = FALSE; -- 忘れずに元に戻す -- トレースファイルが増えすぎた場合のサイズ制限 -- MAX_DUMP_FILE_SIZE でトレースファイルの最大サイズを設定する ALTER SESSION SET MAX_DUMP_FILE_SIZE = '100M'; -- 100MB でトレースを打ち切る -- または ALTER SYSTEM SET MAX_DUMP_FILE_SIZE = '500M'; -- システム全体のデフォルト
まとめ
- ALTER SESSION SET EVENTS ‘10046 trace name context forever, level 12’:バインド変数値と待機イベントを含む最も詳細なトレース。調査目的では level 12 を推奨
- DBMS_MONITOR:DBA 権限で他セッションや、サービス・モジュール単位のトレースを有効にできる。本番でのアプリ調査に使う
- V$DIAG_INFO:トレースファイルのフルパスを確認する。
SELECT name, value FROM V$DIAG_INFO WHERE name = 'Default Trace File' - tkprof の sort=fchela sys=no:経過時間が長い SQL を先に表示する。sys=no で内部処理を除外すると見やすくなる
- tkprof 出力のポイント:①elapsed >> cpu は待機が原因 ②Parse count が多い = ハードパース多発 ③disk が多い = インデックス未使用 ④Fetch count が多い = N+1 問題
- TRACEFILE_IDENTIFIER:トレースファイルに識別子を付けると後から検索しやすくなる
待機イベントの詳細な分析方法は Oracle 待機イベント完全ガイドを参照してください。実行計画の確認には DBMS_XPLAN 完全ガイドも組み合わせて活用してください。AWR・ASH による長期的なパフォーマンス分析は Oracle AWR/ASH 完全ガイドを参照してください。