Plan Header
Plan Header は DBMS_XPLAN.DISPLAY_CURSOR や DISPLAY_AWR が出力する最初の数行で、この計画が「どの SQL で」「いつ取得されたか」を識別するメタ情報です。
| 項目 | 意味 | 影響箇所・着目点 |
|---|---|---|
| SQL_ID | SQL テキストを正規化した 13 桁の識別子 | AWR / V$SQL / V$SQL_PLAN を横断検索する際のキー。バインド変数値が違っても同じ SQL_ID |
| Child Number | 同一 SQL_ID に対して生成された計画バリアントの連番(0 から始まる) | 複数ある場合は異なる環境(NLS設定差・最適化ヒント差 等)で別計画が生成されている |
| Hash Value | 計画ツリー全体のハッシュ値 | 計画が変化していないかを比較するときに使用。AWR では PLAN_HASH_VALUE として保存される |
| Plan取得元 | カーソルキャッシュ (DISPLAY_CURSOR) か AWR (DISPLAY_AWR) かを示す行 | キャッシュから取れない場合は「SQL_ID not found」エラーが出るため AWR を試す |
| Last Active Time / First Load Time | カーソルの最終アクティブ時刻・最初のロード時刻 | この計画がいつの性能問題に対応するかを時系列で確認 |
Child Number が複数ある場合の原因
- NLS_DATE_FORMAT などのセッションレベルパラメータ差
- Bind Peeking の結果として異なるバインド値で異なる計画が生成された
- Adaptive Cursor Sharing(ACS)による再最適化
- DDL 実行後の旧計画がフラッシュされず残存
Plan Table 基本列
Plan Table(ツリー本体)を構成するすべての列の意味を以下にまとめます。フォーマット文字列によって表示される列が異なります。
| 列名 | 意味 | 影響箇所・着目点 |
|---|---|---|
| Id | ステップ番号。アスタリスク(*)付きは Predicate Information に対応する述語あり | Predicate Information との対応付けに使用 |
| Operation | このステップで行われる処理の名称(TABLE ACCESS FULL、INDEX RANGE SCAN 等) | アクセスパスと操作の中心的な情報 |
| Name | 操作の対象オブジェクト名(表名・インデックス名・ビュー名等) | インデックスが使われているかどうかの確認 |
| Rows | オプティマイザが推定した出力行数(E-Rows) | A-Rows との乖離で推定精度を確認 |
| Bytes | 推定出力バイト数 | メモリ消費(PGA)の目安。HASH JOIN / SORT の規模感 |
| Cost (%CPU) | オプティマイザが計算したコスト(括弧内はCPUコスト比率) | 単体の絶対値より相対比較・計画変化の追跡に使う |
| Time | 推定実行時間(hh:mm:ss) | あくまで推定値。実際の所要時間とは大きく乖離することが多い |
| TQ / IN-OUT / PQ Distrib | パラレル実行時のTable Queue番号・通信方向・分配方式 | パラレルの度合いとデータ分配のボトルネック確認 |
| Pstart / Pstop | パーティションプルーニング後の対象パーティション番号(開始/終了) | KEY と表示される場合はパーティションが実行時まで確定しない動的プルーニング |
Id 列 と Operation 列
Id 列 はツリーの各ノードに振られた連番です。Id 0 が最上位(SELECT STATEMENT 等)で、インデントが深いほど子ノード(先に実行される)です。
実行順の読み方
- インデントが最も深いノードから実行される
- 同一深さなら上から下へ
- NESTED LOOPS では外側ループ(上)が駆動表、内側ループ(下)が被駆動表
- HASH JOIN では Build 側(上)を先にハッシュテーブルに展開し、Probe 側(下)を流す
| Operation | 分類 | 意味 |
|---|---|---|
| SELECT STATEMENT | ルートノード | 実行計画ツリーの最上位。コスト欄に最終コストが表示される |
| TABLE ACCESS FULL | アクセスパス | フルテーブルスキャン(セグメント全体を読む) |
| TABLE ACCESS BY INDEX ROWID | アクセスパス | ROWID によるテーブルの行アクセス(インデックス経由) |
| INDEX RANGE SCAN | アクセスパス | インデックスの範囲スキャン |
| NESTED LOOPS | 結合 | 外側ループと内側ループを組み合わせた結合 |
| HASH JOIN | 結合 | ハッシュテーブルを構築してプローブする結合 |
| SORT ORDER BY | ソート | ORDER BY のソート処理 |
| FILTER | サブクエリ | 相関サブクエリの評価。ループ処理になりやすい |
Rows 列 と Bytes 列
Rows はオプティマイザが算出した推定行数(Cardinality)です。これが実際の行数(A-Rows)と大きく乖離すると、選択されるアクセスパスや結合順序が最適でなくなります。
- 読み方: ALLSTATS フォーマットでは E-Rows と A-Rows が並んで表示される。10倍以上乖離するステップが誤推定の根源
- 閾値・注意点: 統計情報が古い・存在しない場合に乖離が大きくなる。動的サンプリングが有効なら Note セクションに記載される
- 関連セクション: Note(dynamic statistics used の確認)/ 統計情報収集(DBMS_STATS)
Bytes はそのステップが出力すると推定されるデータ量です。HASH JOIN の Build 側や SORT 操作の Bytes が大きい場合、PGA が不足して一時領域(TEMP)へ SPILL が発生しやすくなります。
Cost 列 と Time 列
Cost はコストベースオプティマイザ(CBO)が内部で計算した相対的なコスト値です。
- 読み方: 計画間の比較・計画変化前後の比較に使う。同じ SQL の計画が変わった後に Cost が跳ね上がっていれば劣化の可能性
- 閾値・注意点: Cost の絶対値は環境依存のため「1000 が良い・悪い」という判断はできない。%CPU の括弧表記が低いと I/O 支配型の計画
- 関連セクション: V$SQL の ELAPSED_TIME と組み合わせて評価
Time は推定実行時間(hh:mm:ss 形式)です。CBO の内部推定値であり、実際の実行時間とは無関係に近い精度であることが多いです。参考値として扱い、実際の性能は V$SQL の ELAPSED_TIME や AWR の SQL Statistics で確認します。
Pstart / Pstop 列(パーティション)
パーティション表に対するアクセスで出現します。オプティマイザがプルーニング後に読み込むパーティション範囲を示します。
| 値 | 意味 | 着目点 |
|---|---|---|
| 数値(例: 1, 3) | 静的プルーニング。コンパイル時にパーティション番号が確定している | 条件が定数リテラルの場合に発生。最も効率的 |
| KEY | 動的プルーニング。バインド変数等で実行時にパーティション番号が決まる | バインド変数プルーニング。実行時に絞り込まれるため計画上は全体に見えても実際は少数パーティション |
| KEY (SQ) | サブクエリの結果でプルーニング | サブクエリが返す値範囲によってパーティション数が変動 |
| ROW REMOVE ITR | Iterator。ループ処理で各行のパーティションへアクセス | NESTED LOOPS の内側でパーティションキーが駆動表の列の場合に出現。効率良し |
| 1 〜 最大パーティション数 | 全パーティションスキャン(プルーニングなし) | WHERE 句にパーティションキーが含まれていないと発生。大量データ処理の兆候 |