タイトル: 索引の再作成
SEOタイトル: Oracle 索引 (Index) の再作成完全ガイド
| この記事の要点 |
|
索引の再作成 (REBUILD) とは
Oracle のインデックスは、大量の更新・削除が繰り返されるとリーフブロックに空き領域 (フラグメンテーション) が発生し、検索性能が劣化します。ALTER INDEX ... REBUILD は既存インデックスから新しい B-Tree を構築し直し、断片化を解消するためのコマンドです。
基本構文
-- 最もシンプルな再構築
ALTER INDEX idx_users_email REBUILD;
-- オンライン再構築 (Oracle 11g以降、推奨)
ALTER INDEX idx_users_email REBUILD ONLINE;
-- 別の表領域に移動しつつ再構築
ALTER INDEX idx_users_email REBUILD TABLESPACE users_idx_ts;
-- 並列度を指定して高速化
ALTER INDEX idx_users_email REBUILD PARALLEL 4;
-- 圧縮しつつ再構築
ALTER INDEX idx_users_email REBUILD COMPRESS;
-- ログ無しで高速化 (リカバリ不能になるので注意)
ALTER INDEX idx_users_email REBUILD NOLOGGING;
再構築 (REBUILD) vs 再作成 (DROP + CREATE)
| 項目 | REBUILD | DROP + CREATE |
|---|---|---|
| 排他ロック | ONLINE 指定で回避可能 | DROP の瞬間に完全消失 |
| ディスク使用量 | 旧 + 新で一時的に 2 倍必要 | 新領域のみ |
| 主キー / 一意制約 | 制約はそのまま維持 | 制約も削除される → 再定義必要 |
| ヒント / 統計情報 | 引き継がれる | リセットされる |
| 処理速度 | 既存索引をソート済み入力として高速 | テーブル全走査が必要 |
原則として REBUILD ONLINE を使い、DROP + CREATE は索引の構成 (列順・タイプ) を変更したい場合のみに留めます。
断片化の確認
-- インデックスの構造を解析
ANALYZE INDEX idx_users_email VALIDATE STRUCTURE;
-- 結果は INDEX_STATS ビューで確認 (セッション内のみ有効)
SELECT
name,
height, -- B-Tree の高さ (4以上で深すぎ)
blocks, -- 確保ブロック数
lf_rows, -- リーフ行数
lf_blks, -- リーフブロック数
del_lf_rows, -- 削除済みリーフ行
del_lf_rows_len, -- 削除済み行のサイズ
used_space,
pct_used -- 使用率 (50%未満で再構築検討)
FROM index_stats;
-- DBMS_SPACE.SPACE_USAGE で詳細な空き状況を取得
DECLARE
unformatted_blocks NUMBER;
unformatted_bytes NUMBER;
fs1_blocks NUMBER; fs1_bytes NUMBER;
fs2_blocks NUMBER; fs2_bytes NUMBER;
fs3_blocks NUMBER; fs3_bytes NUMBER;
fs4_blocks NUMBER; fs4_bytes NUMBER;
full_blocks NUMBER; full_bytes NUMBER;
BEGIN
DBMS_SPACE.SPACE_USAGE(
segment_owner => 'APP',
segment_name => 'IDX_USERS_EMAIL',
segment_type => 'INDEX',
unformatted_blocks => unformatted_blocks,
unformatted_bytes => unformatted_bytes,
fs1_blocks => fs1_blocks, fs1_bytes => fs1_bytes,
fs2_blocks => fs2_blocks, fs2_bytes => fs2_bytes,
fs3_blocks => fs3_blocks, fs3_bytes => fs3_bytes,
fs4_blocks => fs4_blocks, fs4_bytes => fs4_bytes,
full_blocks => full_blocks, full_bytes => full_bytes
);
END;
/
再構築が必要な目安
- PCT_USED < 50% → 断片化が進行、再構築を検討
- DEL_LF_ROWS / LF_ROWS > 20% → 削除済み行が多すぎ
- HEIGHT >= 4 → B-Tree が深くなりすぎ、行数のわりに非効率
- 定期的に大量 DELETE / UPDATE するテーブル → 月次・四半期で再構築
ONLINE オプションの注意
Oracle 11g 以降では REBUILD ONLINE により DML をブロックせず再構築できますが、内部的には以下が起こります:
- 新しい索引セグメントが旧索引と並行して構築される (ディスク 2 倍必要)
- 再構築中に発生した DML は ジャーナル表に記録され、最後に適用
- 適用フェーズで一瞬だけ排他ロックが発生 (通常は数秒)
- 大量更新の最中はジャーナルが肥大化 → 業務閑散期に実施推奨
パーティション索引の再構築
-- ローカルパーティション索引の特定パーティションのみ
ALTER INDEX idx_orders_local REBUILD PARTITION p_2025_q1 ONLINE;
-- 全パーティション (一括)
ALTER INDEX idx_orders_local REBUILD;
-- グローバル索引で UNUSABLE 状態を解消
ALTER TABLE orders MOVE PARTITION p_2024_q4 UPDATE GLOBAL INDEXES;
運用バッチ例
-- 断片化率が高い索引を自動抽出して再構築する PL/SQL
DECLARE
v_sql VARCHAR2(500);
BEGIN
FOR rec IN (
SELECT i.owner, i.index_name
FROM dba_indexes i
WHERE i.owner = 'APP'
AND i.status = 'VALID'
) LOOP
v_sql := 'ANALYZE INDEX ' || rec.owner || '.' || rec.index_name
|| ' VALIDATE STRUCTURE';
EXECUTE IMMEDIATE v_sql;
FOR s IN (SELECT pct_used, height FROM index_stats) LOOP
IF s.pct_used < 50 OR s.height >= 4 THEN
v_sql := 'ALTER INDEX ' || rec.owner || '.' || rec.index_name
|| ' REBUILD ONLINE';
DBMS_OUTPUT.PUT_LINE('Rebuilding: ' || rec.index_name);
EXECUTE IMMEDIATE v_sql;
END IF;
END LOOP;
END LOOP;
END;
/
他 DBMS の同等コマンド
| DB | コマンド | 備考 |
|---|---|---|
| Oracle | ALTER INDEX ... REBUILD ONLINE | 11g+ でオンライン可 |
| MySQL (InnoDB) | OPTIMIZE TABLE tbl; / ALTER TABLE tbl ENGINE=InnoDB; | テーブル全体を再構築 |
| PostgreSQL | REINDEX INDEX idx; / REINDEX CONCURRENTLY | 12+ でオンライン化対応 |
| SQL Server | ALTER INDEX idx ON tbl REBUILD WITH (ONLINE = ON) | Enterprise Edition で ONLINE 可 |
| DB2 | REORG INDEXES ALL FOR TABLE tbl |
FAQ
Q: REBUILD と COALESCE の違いは?
A: COALESCE は隣接するリーフブロックの空き領域だけを結合 (オンライン・低負荷)、REBUILD は索引全体を再構築 (リソース要求大・ディスク 2 倍)。日常メンテは COALESCE、深刻な断片化は REBUILD。
Q: 再構築中にエラーで止まったらどうなる?
A: 旧索引はそのまま残るので検索は継続できます。新索引のセグメントが残骸として残る場合があるので DBA_SEGMENTS で確認し PURGE してください。
Q: 主キー索引を REBUILD すると制約に影響する?
A: 影響なし。主キー・一意制約は索引に紐付くが、REBUILD では制約自体は維持されます。DROP すると制約も消えます。