「新しいインデックスを追加したいが、本番環境で影響を調べてから適用したい」「使われていないインデックスを削除したいが、万一のために少し残しておきたい」という場面で役立つのが非表示インデックス(Invisible Index)です。
非表示インデックスはデータ構造として維持されますが、オプティマイザには見えないため通常の実行計画に影響しません。セッション単位で有効化することで、本番サービスに影響なく新インデックスの効果を安全に検証できます。
この記事でわかること
- 非表示インデックスの仕組みと通常インデックスとの違い
- INVISIBLE 句でインデックスを作成・既存インデックスを非表示にする方法
- USE_INVISIBLE_INDEXES パラメータで特定セッションのみ非表示インデックスを使う方法
- DBA_INDEXES の visibility 列でインデックスの表示状態を確認する
- 廃止候補インデックスの安全な無効化 → 削除の手順
非表示インデックスとは
| 項目 | 通常インデックス | 非表示インデックス(Invisible) |
|---|---|---|
| オプティマイザの利用 | 利用される | 利用されない(デフォルト) |
| DML 時のメンテナンス | 自動更新される | 自動更新される(データ整合性は維持) |
| UNIQUE 制約の強制 | される | される(UNIQUE インデックスの場合) |
| 強制使用方法 | ヒントまたはデフォルト | USE_INVISIBLE_INDEXES=TRUE または INDEX ヒント |
| 導入バージョン | — | Oracle 11g Release 1 以降 |
非表示インデックスを作成・変更する
INVISIBLE 句でインデックスを作成する
-- 非表示インデックスを作成する(オプティマイザには見えない) CREATE INDEX emp_dept_ix ON employees(department_id) INVISIBLE; -- 関数ベースの非表示インデックスも同様に作成できる CREATE INDEX emp_upper_name_ix ON employees(UPPER(last_name)) INVISIBLE; -- 既存のインデックスを非表示に変更する(DROP 不要) ALTER INDEX emp_salary_ix INVISIBLE; -- 非表示インデックスを可視化する(オプティマイザから見えるようにする) ALTER INDEX emp_salary_ix VISIBLE; -- インデックスの表示状態を確認する SELECT index_name, table_name, visibility, status, num_rows FROM DBA_INDEXES WHERE table_name = 'EMPLOYEES' ORDER BY index_name; -- VISIBILITY: VISIBLE(通常)/ INVISIBLE(非表示)
USE_INVISIBLE_INDEXES で非表示インデックスをテストする
セッションレベルで USE_INVISIBLE_INDEXES=TRUE に設定すると、そのセッションのみ非表示インデックスが有効になります。他のセッション(本番処理)には影響しないため、安全に効果を検証できます。
セッションで非表示インデックスを有効にして効果を検証する
-- セッションレベルで非表示インデックスを有効化する ALTER SESSION SET use_invisible_indexes = TRUE; -- 非表示インデックスが使われるか実行計画を確認する EXPLAIN PLAN FOR SELECT employee_id, last_name FROM employees WHERE department_id = 50; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(format => 'TYPICAL')); -- インデックス利用時: INDEX RANGE SCAN が表示される -- USE_INVISIBLE_INDEXES=FALSE の場合: TABLE ACCESS FULL になる可能性がある -- セッションを通常設定に戻す ALTER SESSION SET use_invisible_indexes = FALSE; -- 現在の設定を確認する SHOW PARAMETER use_invisible_indexes;
INDEX ヒントで特定 SQL のみ非表示インデックスを強制利用する
-- USE_INVISIBLE_INDEXES をセッション全体に有効化せず、
-- 特定の SQL だけ非表示インデックスを使う場合は INDEX ヒントを使う
SELECT /*+ INDEX(e emp_dept_ix) */
employee_id, department_id
FROM employees e
WHERE department_id = 50;
-- INDEX ヒントで指定したインデックスは INVISIBLE でも使用される
廃止候補インデックスを安全に無効化・削除する手順
インデックスが本当に使われていないかどうかを確認してから削除するのが安全な手順です。非表示インデックスを使うことで、削除前に「使われないこと」を本番環境で確認できます。
インデックスの使用状況を監視する(V$OBJECT_USAGE)
-- インデックスの使用状況モニタリングを開始する ALTER INDEX emp_salary_ix MONITORING USAGE; -- アプリケーションを一定期間(数日~数週間)稼働させてから確認する SELECT index_name, table_name, monitoring, used, start_monitoring, end_monitoring FROM V$OBJECT_USAGE WHERE index_name = 'EMP_SALARY_IX'; -- USED = YES → 期間中に1回以上使われた -- USED = NO → 期間中に使われなかった(廃止候補) -- モニタリングを停止する ALTER INDEX emp_salary_ix NOMONITORING USAGE;
廃止候補インデックスを非表示にして本番で検証する(推奨手順)
-- ステップ1: 廃止候補インデックスを非表示にする(削除しない) ALTER INDEX emp_salary_ix INVISIBLE; -- ステップ2: 一定期間(1~2週間)本番稼働させてパフォーマンスを監視する -- → 問題が発生した場合は ALTER INDEX emp_salary_ix VISIBLE; で即座に戻せる -- ステップ3: 問題がなければインデックスを削除する DROP INDEX emp_salary_ix; -- ステップ4: 念のためインデックス削除後の実行計画を確認する EXPLAIN PLAN FOR SELECT * FROM employees WHERE salary > 10000; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(format => 'TYPICAL'));
システムレベルで USE_INVISIBLE_INDEXES を設定する場合
システム全体で非表示インデックスを有効化する(本番では通常不要)
-- システムレベルで全セッションに非表示インデックスを有効化する -- 通常は推奨しない(新機能テスト・緊急対応時のみ) ALTER SYSTEM SET use_invisible_indexes = TRUE SCOPE=MEMORY; -- 確認後は FALSE に戻す ALTER SYSTEM SET use_invisible_indexes = FALSE SCOPE=MEMORY; -- SCOPE=MEMORY のみ(再起動後は元に戻る)
まとめ
- 非表示インデックスはデータ整合性・UNIQUE 制約は維持しつつ、オプティマイザには見えない状態にできる
- CREATE INDEX … INVISIBLE:作成時から非表示に設定。ALTER INDEX … INVISIBLE で既存インデックスを非表示化できる
- USE_INVISIBLE_INDEXES=TRUE:セッション単位で非表示インデックスを有効化してテストできる(他のセッションへの影響なし)
- 廃止手順:INVISIBLE で非表示→本番稼働確認→問題なければ DROP。問題発生時は VISIBLE に戻すだけで即時対応できる
- V$OBJECT_USAGE の MONITORING USAGE でインデックスが実際に使われているかを本番で確認できる
インデックスの種類・設計・再構築については インデックス完全ガイドを参照してください。実行計画の詳細確認は DBMS_XPLAN完全ガイドも参照してください。