Predicate Information とは
Predicate Information は Plan Table のアスタリスク(*)付きステップに対応して、そのステップでどのような条件が適用されるかを詳述するセクションです。Plan Table だけでは「このインデックスが何の条件で使われているか」がわからないため、このセクションと合わせて読むことが不可欠です。
表示形式は以下のとおりです。
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("DEPT_ID"=:B1)
3 - filter("STATUS"='ACTIVE' AND "CREATED_AT">=TRUNC(SYSDATE)-30)
access 述語 と filter 述語の違い
| 種類 | 意味 | インデックスとの関係 | 着目点 |
|---|---|---|---|
| access | インデックス(またはクラスタ/ハッシュクラスタ)のキーを使って範囲を絞り込む条件。B-Tree をたどる出発点 | インデックスが列の左端から順に使われている条件のみが access になる | access の列がインデックスの先頭列から連続していることを確認。欠落があると後続列が filter に落ちる |
| filter | インデックスから取得した行(または TABLE ACCESS から取得した行)に対してメモリ上で行ごとに評価するフィルタ | インデックスで絞り込んだ後の「残り削り」。インデックスの恩恵は受けない | filter の行数が多い(access で絞り込めていない)場合はインデックス設計の見直しを検討 |
access と filter の具体例
インデックスが (DEPT_ID, STATUS, CREATED_AT) の複合インデックスとして作成されている場合:
WHERE DEPT_ID = :B1→ access(先頭列の等値、最も効率的)WHERE DEPT_ID = :B1 AND STATUS = 'ACTIVE'→ 両方 accessWHERE DEPT_ID = :B1 AND CREATED_AT >= SYSDATE - 30→ DEPT_ID は access、CREATED_AT は filter(STATUS が間に挟まるため連続しない)WHERE STATUS = 'ACTIVE'のみ → filter(先頭列 DEPT_ID がない → INDEX FULL SCAN か Full Table Scan)
カバリングインデックスの確認方法
カバリングインデックス(Index Only Access)とは、SELECT で取得したい列がすべてインデックスに含まれているため、TABLE ACCESS BY INDEX ROWID が不要になる状態です。実行計画では TABLE ACCESS BY INDEX ROWID ノードが出現しません。
- 確認方法: INDEX スキャンノードの直上に TABLE ACCESS BY INDEX ROWID がない場合はカバリングインデックスが成立している
- Column Projection との組み合わせ: Projection でインデックス列のみが流れていることを確認するとより確実
- 注意点: NULL 値を含む列はデフォルトの B-Tree インデックスに含まれないため、NULL がある列は SELECT に入れてもインデックスで取得できないことがある
問題となる述語パターン
| 問題パターン | 実行計画での症状 | 改善策 |
|---|---|---|
| 関数適用(TO_DATE、UPPER 等) | インデックス列が TO_DATE("COL_DATE") のように filter に落ちる。Full Scan になりやすい |
Function-Based Index(関数インデックス)を作成するか、クエリ側で逆変換する |
| 型の暗黙変換 | VARCHAR2 列に数値リテラルを渡すと TO_NUMBER("COL") 変換が発生し filter に落ちる |
リテラルを文字列(シングルクォート)で渡す・バインド変数の型を一致させる |
| NOT EQUAL(<>, !=) | インデックスが使えず filter になる(範囲が定義できないため) | NOT NULL が既知の場合は < と > の OR に書き換えると Range Scan で対応可能な場合あり |
| LIKE '%後方一致%' | 先頭ワイルドカードで B-Tree の開始点が定まらず filter になる | Oracle Text(CONTAINS)またはアプリ側の検索ロジック変更 |
| IS NULL / IS NOT NULL | B-Tree には NULL が格納されないため、IS NULL では通常インデックスを使えない | Bitmap Index・NULL を含む複合インデックス(NOT NULL の列と組み合わせ) |
Column Projection セクション
Column Projection は DBMS_XPLAN のフォーマットに 'ALL' を指定した場合に出力されます。各ステップが親へ渡す列のリストを示します。
出力例
Column Projection Information (identified by operation id): ----------------------------------------------------------- 1 - (#keys=0) "EMP_ID"[NUMBER,22], "EMP_NAME"[VARCHAR2,100] 2 - "DEPT_ID"[NUMBER,22], "EMP_ID"[NUMBER,22], "EMP_NAME"[VARCHAR2,100] 3 - "DEPT_ID"[NUMBER,22]
| 確認ポイント | 意味・着目点 |
|---|---|
| 不要な大型列の混入 | CLOB / BLOB / VARCHAR2(4000) などの大型列が上位ステップまで流れていないか確認。SELECT * の使用で発生しやすい |
| ROWID の受け渡し | ROWID が流れている場合、その後に TABLE ACCESS BY USER ROWID が続く設計かを確認 |
| #keys=N | N はこのステップが親への結合キーとして使用する列数。ソート・ハッシュ結合のキー列を識別できる |
| カバリングインデックスの確認 | INDEX スキャンのステップで SELECT に必要な列がすべて投影されており、テーブルへのフォールバックがない場合はカバリング成立 |