アクセスパスの選択基準
オプティマイザはコスト(I/O + CPU)を最小化するアクセスパスを選択します。選択に影響する主な要素は次のとおりです。
- 選択率(Selectivity): WHERE 条件で絞り込める行の割合。低いほどインデックスが有利
- 統計情報の鮮度: 行数・NDV(NULL以外のユニーク値数)・ヒストグラムが古いと誤った選択率を算出する
- クラスタリングファクタ: インデックス順と物理行順の一致度。高い(悪い)と ROWID アクセス時のI/Oが増大
- 初期化パラメータ:
DB_FILE_MULTIBLOCK_READ_COUNTが大きいとフルスキャンのコストが下がる
TABLE ACCESS FULL(フルスキャン)
何を表すか: セグメント(表)の全ブロックを先頭から順に読み込む操作。マルチブロック読込(db file scattered read)が発生する。
- 読み方: Rows が多い(大量データ取得)場合や、WHERE 句が存在しない場合は正常。少量データ取得で Full Scan が選ばれていたら要調査
- 正常パターン: 全体の大多数の行を取得する OLAP 系クエリ・集計バッチ処理
- 問題パターン: 1〜数行のみ取得したいのに Full Scan が選ばれている(統計情報の誤り・インデックス未作成・関数で列を加工してインデックスが効かない)
- 閾値・注意点: バッファキャッシュが小さい環境では Full Scan が多いと
db file scattered read待機が増加する - 関連: Predicate Information の filter 条件 / Segment Statistics(Reads Top)
INDEX UNIQUE SCAN
何を表すか: 一意インデックス(UNIQUE INDEX)を使い、条件に合う 1 行のみを確実に取得するスキャン。
- 読み方: Rows = 1 が典型。PRIMARY KEY や UNIQUE 制約の列を等値条件(=)で指定したときに選ばれる最も効率的なアクセスパス
- 正常パターン: PK 検索、UNIQUE 列の等値条件
- 問題パターン: ほとんどない。ただし ROWID アクセスへの繋ぎ(TABLE ACCESS BY INDEX ROWID)で実表へのアクセスが発生することに注意
- 閾値・注意点: Cost = 1〜2 が標準的。大幅に高い場合はクラスタリングファクタが悪化している可能性
- 関連: Predicate Information の access 条件
INDEX RANGE SCAN
何を表すか: インデックス内の特定範囲の葉ブロックを順に辿るスキャン。複数行が返ることが前提。
- 読み方: Predicate Information の access 条件に範囲述語(>=、<=、BETWEEN、LIKE 'prefix%' 等)が含まれる
- 正常パターン: 数%〜数十%の選択率でインデックスが有効な場合
- 問題パターン: Rows が多い(選択率が高い)のに Range Scan が選ばれている → Full Scan の方が効率的な可能性。統計情報の誤りで過小推定されていることが多い
- 閾値・注意点: 結果の行数が多いほど、後続の TABLE ACCESS BY INDEX ROWID でのランダム I/O が増加する
- 関連: クラスタリングファクタ(DBA_INDEXES.CLUSTERING_FACTOR)
| Operation | 意味 | 注意点 |
|---|---|---|
| INDEX RANGE SCAN | 通常の範囲スキャン | 昇順・降順両対応 |
| INDEX RANGE SCAN DESCENDING | インデックスを降順に辿る | ORDER BY ... DESC や MAX() 最適化で出現 |
| INDEX RANGE SCAN (MIN/MAX) | MIN/MAX 最適化で先頭/末尾 1 エントリのみ取得 | Cost は非常に低くなる |
INDEX FULL SCAN / INDEX FAST FULL SCAN
INDEX FULL SCAN: インデックスツリーの全エントリをソート済み順(ルート→リーフ順)に読む。ORDER BY 排除や DISTINCT 最適化で使われる。
INDEX FAST FULL SCAN: インデックスセグメントのすべてのブロックをマルチブロック読込で読む。ソート順は保証されない。COUNT(*) や INDEX のみで完結する検索(Index Only Access)で使われる。
| 比較項目 | INDEX FULL SCAN | INDEX FAST FULL SCAN |
|---|---|---|
| 読み込み順序 | ソート済み(B-Tree 順) | 物理ブロック順(ソート保証なし) |
| 読み込み方式 | シングルブロック読込 | マルチブロック読込(高速) |
| ORDER BY 排除 | 可(インデックス順が ORDER BY と一致する場合) | 不可 |
| 典型的な用途 | ORDER BY / DISTINCT 最適化・MIN/MAX | COUNT(*) / INDEX Only のカバリングインデックス |
| 問題パターン | 全行 = TABLE ACCESS FULL の方が速い可能性 | テーブル参照不要な検索なのにテーブルアクセスが追加されていたら設計見直し |
INDEX SKIP SCAN
何を表すか: 複合インデックスの先頭列が WHERE 条件に含まれない場合に、先頭列の異なる値ごとにインデックスを複数回スキャンして結合する手法。
- 読み方: 先頭列のカーディナリティが低い(値の種類が少ない)場合にコスト的に有効と判断されて選ばれる
- 正常パターン: 先頭列が性別(M/F 等)・区分コード(数種類)など低カーディナリティで、後続列で高選択率フィルタがかかる場合
- 問題パターン: 先頭列のカーディナリティが実際は高い(統計情報が古い)のに Skip Scan が選ばれた場合は非効率
- 閾値・注意点:
INDEX RANGE SCANに置き換えたい場合は先頭列を条件に追加するか、後続列単独のインデックスを作成する
TABLE ACCESS BY INDEX ROWID / BY USER ROWID
TABLE ACCESS BY INDEX ROWID: インデックスから得た ROWID を使い、実表の行を 1 件ずつ読み込む操作。インデックスを使うと必ずこの操作が続く(カバリングインデックスの場合を除く)。
- 読み方: Rows が多い = ランダム I/O が多い。100 行以上取得する ROWID アクセスは Full Scan より遅くなる可能性がある
- 問題パターン: ループ回数 × ROWID アクセス = 大量のシングルブロック読込。
db file sequential read待機の原因 - 閾値・注意点: Predicate Information に filter 条件が多い(インデックスで絞り切れていない)と、このステップで大量の行が取得された後にフィルタされる
- 関連: クラスタリングファクタ / INDEX RANGE SCAN
TABLE ACCESS BY USER ROWID: アプリケーションが ROWID を直接指定して 1 行にアクセスする方式。通常は開発者が意図的に使う(パフォーマンス最適化・一時バッチ処理等)。
TABLE ACCESS SAMPLE
SAMPLE 句(SELECT … FROM T SAMPLE(10))を使ったサンプリングスキャン。統計情報収集や APPROXIMATION クエリで使われます。本番業務クエリでは通常出現しないため、もし見かけたらアプリロジックのレビューが必要です。