Oracleインデックスの確認・作成・再構築方法【無効化・断片化対策まで】

当ページのリンクには広告が含まれています。

「インデックスが効いていない」「テーブルが遅い」「断片化が怖い」——Oracleのインデックスは正しく管理しないとパフォーマンスに直結します。本記事では現場DBAが必ず知っておくべきインデックスの確認・作成・再構築・無効化を完全解説します。

目次

1. Oracleインデックスの基本 {#about}

インデックスとは、テーブルの特定列に対して作成される「索引」です。フルスキャンを避けて高速に行を特定できます。

インデックスの種類:

種類特徴
B-treeインデックスデフォルト。等値・範囲検索に強い
ユニークインデックス値の重複を許さない(PRIMARY KEYに自動作成)
複合インデックス複数列をまとめたインデックス
ビットマップインデックス低カーディナリティ列向け(DWH環境)
関数ベースインデックスUPPER(name) などの式に対して作成

カーディナリティとは列の値の種類の多さ。「性別(男/女)」は低カーディナリティ、「社員番号」は高カーディナリティ。B-treeインデックスは高カーディナリティ列に効果的。


2. インデックスの一覧を確認するSQL {#check-index}

自分のスキーマのインデックスを確認

-- USER_INDEXESで確認(自分のスキーマ)
SELECT
    INDEX_NAME,
    TABLE_NAME,
    INDEX_TYPE,
    UNIQUENESS,
    STATUS,
    LAST_ANALYZED
FROM USER_INDEXES
ORDER BY TABLE_NAME, INDEX_NAME;

出力例:

INDEX_NAME          TABLE_NAME    INDEX_TYPE  UNIQUENESS  STATUS  LAST_ANALYZED
------------------  ------------  ----------  ----------  ------  -------------
PK_EMPLOYEES        EMPLOYEES     NORMAL      UNIQUE      VALID   2026-05-01
IDX_EMP_DEPT_ID     EMPLOYEES     NORMAL      NONUNIQUE   VALID   2026-05-01
IDX_EMP_NAME        EMPLOYEES     NORMAL      NONUNIQUE   VALID   (null)
  • STATUS = VALID:正常
  • STATUS = UNUSABLE:無効化中(クエリで使われない)
  • LAST_ANALYZED が null:統計情報未収集(要注意)

インデックスの列構成を確認

-- どの列にインデックスが付いているか確認
SELECT
    INDEX_NAME,
    COLUMN_POSITION,
    COLUMN_NAME,
    DESCEND
FROM USER_IND_COLUMNS
WHERE TABLE_NAME = 'EMPLOYEES'
ORDER BY INDEX_NAME, COLUMN_POSITION;

出力例:

INDEX_NAME        COLUMN_POSITION  COLUMN_NAME   DESCEND
----------------  ---------------  ------------  -------
IDX_EMP_DEPT_ID   1                DEPT_ID       ASC
PK_EMPLOYEES      1                EMPLOYEE_ID   ASC

DBA権限で全スキーマのインデックスを確認

-- DBA_INDEXESで全スキーマを確認(DBA権限が必要)
SELECT
    OWNER,
    INDEX_NAME,
    TABLE_NAME,
    STATUS,
    LAST_ANALYZED
FROM DBA_INDEXES
WHERE OWNER = 'SCOTT'  -- スキーマ名を指定
ORDER BY TABLE_NAME;

3. インデックスを作成する(CREATE INDEX) {#create-index}

通常のインデックス

-- 単一列インデックス
CREATE INDEX IDX_EMP_DEPT_ID
ON EMPLOYEES(DEPT_ID);

-- 複合インデックス(カーディナリティが高い列を先頭に)
CREATE INDEX IDX_EMP_DEPT_JOB
ON EMPLOYEES(DEPT_ID, JOB_ID);

-- ユニークインデックス
CREATE UNIQUE INDEX UNX_EMP_EMAIL
ON EMPLOYEES(EMAIL);

関数ベースインデックス

-- UPPER関数を使った検索に対応するインデックス
CREATE INDEX IDX_EMP_NAME_UPPER
ON EMPLOYEES(UPPER(LAST_NAME));

-- このインデックスが有効になるクエリ例
SELECT * FROM EMPLOYEES WHERE UPPER(LAST_NAME) = 'SMITH';

オンラインインデックス作成(ONLINE句)

-- 本番稼働中のテーブルにインデックスを追加する場合
-- ONLINE句を付けるとDMLをブロックしない(時間はかかる)
CREATE INDEX IDX_EMP_HIRE_DATE
ON EMPLOYEES(HIRE_DATE)
ONLINE;

注意:ONLINE句なしで大きなテーブルにインデックスを作成すると、テーブルロックが発生してDML(INSERT/UPDATE/DELETE)が止まります。本番では必ずONLINEを付けてください。

表領域を指定してインデックスを作成

-- インデックス用テーブルスペースに格納(推奨)
CREATE INDEX IDX_EMP_DEPT_ID
ON EMPLOYEES(DEPT_ID)
TABLESPACE INDX;

4. インデックスを再構築する(REBUILD) {#rebuild}

インデックスは更新を重ねると断片化します。ALTER INDEX ... REBUILD で再構築します。

基本の再構築

-- インデックスを再構築
ALTER INDEX IDX_EMP_DEPT_ID REBUILD;

-- オンラインで再構築(本番環境向け)
ALTER INDEX IDX_EMP_DEPT_ID REBUILD ONLINE;

複数インデックスをまとめて再構築するスクリプト

-- テーブル単位でインデックスを一括再構築するSQLを生成
SELECT
    'ALTER INDEX ' || INDEX_NAME || ' REBUILD ONLINE;'
FROM USER_INDEXES
WHERE TABLE_NAME = 'EMPLOYEES'
  AND STATUS = 'VALID';

生成されたSQLをコピーして実行します。

UNUSABLE状態のインデックスを再構築

-- UNUSABLE状態のインデックスを一括再構築するSQLを生成
SELECT
    'ALTER INDEX ' || OWNER || '.' || INDEX_NAME || ' REBUILD ONLINE;'
FROM DBA_INDEXES
WHERE STATUS = 'UNUSABLE';

5. インデックスの無効化と有効化 {#unusable}

大量データのバッチINSERT時にインデックスを無効化すると処理が大幅に速くなります。

インデックスを無効化(UNUSABLE)

-- インデックスをUSUNABLE状態にする(クエリで使われなくなる)
ALTER INDEX IDX_EMP_DEPT_ID UNUSABLE;

UNUSABLE状態でDMLを実行しても、インデックスは更新されません(エラーも出ません)。
ただし SKIP_UNUSABLE_INDEXES = FALSE の場合はエラーになるので注意。

バッチ処理後にREBUILDで有効化

-- 大量INSERTが終わったらREBUILDで再構築して有効化
ALTER INDEX IDX_EMP_DEPT_ID REBUILD ONLINE;

インデックス無効化を使ったバッチ処理の流れ

-- 1. インデックスを無効化
ALTER INDEX IDX_EMP_DEPT_ID UNUSABLE;
ALTER INDEX IDX_EMP_NAME UNUSABLE;

-- 2. 大量INSERTを実行(高速化)
INSERT /*+ APPEND */ INTO EMPLOYEES SELECT * FROM EMPLOYEES_STAGE;
COMMIT;

-- 3. インデックスを再構築して有効化
ALTER INDEX IDX_EMP_DEPT_ID REBUILD ONLINE;
ALTER INDEX IDX_EMP_NAME REBUILD ONLINE;

6. インデックスの断片化を確認する {#fragmentation}

ANALYZE INDEX VALIDATE STRUCTUREで断片化を確認

-- 分析実行(INDEX_STATSに結果が入る)
ANALYZE INDEX IDX_EMP_DEPT_ID VALIDATE STRUCTURE;

-- 断片化率を確認
SELECT
    NAME,
    HEIGHT,         -- B-treeの深さ(4以上は要注意)
    BLOCKS,         -- 使用ブロック数
    LF_ROWS,        -- リーフ行数(有効データ)
    DEL_LF_ROWS,    -- 削除済みリーフ行数
    ROUND(DEL_LF_ROWS / DECODE(LF_ROWS, 0, 1, LF_ROWS) * 100, 2) AS 断片化率
FROM INDEX_STATS;

出力例:

NAME              HEIGHT  BLOCKS  LF_ROWS  DEL_LF_ROWS  断片化率
----------------  ------  ------  -------  -----------  ------
IDX_EMP_DEPT_ID   3       128     50000    18000        36.00  ← 要再構築

目安:

  • 断片化率 20%以上 → REBUILDを検討
  • HEIGHT 4以上 → REBUILDを推奨

7. インデックスを削除する(DROP INDEX) {#drop-index}

-- インデックスを削除
DROP INDEX IDX_EMP_DEPT_ID;

-- 存在する場合のみ削除(12c以降)
DROP INDEX IF EXISTS IDX_EMP_DEPT_ID;

注意:PRIMARY KEY制約に紐づくインデックスはDROP INDEXでは削除できません。制約ごと削除する必要があります。

-- PRIMARY KEY制約ごと削除する場合
ALTER TABLE EMPLOYEES DROP PRIMARY KEY;
-- または
ALTER TABLE EMPLOYEES DROP CONSTRAINT PK_EMPLOYEES;

8. よくあるトラブルとエラー対処 {#errors}

ORA-01452:ユニーク制約違反でインデックスが作れない

ORA-01452: 一意なインデックスを作成できません - 重複するキーが見つかりました
-- 重複データを確認してから削除
SELECT EMAIL, COUNT(*)
FROM EMPLOYEES
GROUP BY EMAIL
HAVING COUNT(*) > 1;

ORA-08102:インデックスのROWIDが不正

ORA-08102: インデックス・キーが見つかりません

インデックスとテーブルの整合性が壊れている状態。REBUILDが有効です。

ALTER INDEX IDX_EMP_DEPT_ID REBUILD;

それでも解消しない場合はDROP → CREATE INDEXで再作成してください。

インデックスが使われない(フルスキャンになる)

実行計画を確認して原因を特定します。

EXPLAIN PLAN FOR
SELECT * FROM EMPLOYEES WHERE DEPT_ID = 10;

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

インデックスが使われない主な原因:

原因対処
統計情報が古いDBMS_STATS.GATHER_TABLE_STATSで更新
WHERE句に関数使用(UPPER(列名)など)関数ベースインデックスを作成
暗黙の型変換(文字列↔数値)バインド変数の型を一致させる
テーブルが小さい(フルスキャンが速い)そのままでOK
カーディナリティが低すぎる別のアクセス方法を検討

9. まとめ:インデックス管理チェックリスト {#summary}

□ USER_INDEXES で STATUS=UNUSABLE のインデックスがないか確認
□ LAST_ANALYZED が古い(または null)のインデックスの統計情報を更新
□ 断片化率 20% 以上のインデックスは REBUILD
□ HEIGHT が 4 以上になっているインデックスは REBUILD
□ 大量バッチ前は UNUSABLE → バッチ後に REBUILD の手順を徹底
□ 本番環境での REBUILD は必ず ONLINE 句を付ける
□ インデックスが多すぎるとDMLが遅くなる → 不要なインデックスは DROP

関連記事:

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

ITの事や自分の経験談など綴っていきたいと思っています。

コメント

コメントする

CAPTCHA


目次