【完全ガイド】ORA-08102: index key not found の原因と解決方法|インデックス破損・REBUILD の罠 徹底解説
- 作成日 2026.09.03
- Oracle Database
Oracle DBA が本番運用中に突然遭遇する深刻なインデックス破損エラー:
DELETE FROM limits WHERE acct_id = 1496605012;
*
ERROR at line 1:
ORA-08102: index key not found, obj# 7941, file 11, block 398468 (2)
**「インデックスにキーが見つからない」**というシンプルなメッセージ。インデックスとテーブルの深刻な不整合を示す重大エラーです:
- インデックスに登録されるべきキーが物理的に欠落
- テーブルとインデックスのメタデータ不整合
- DML 全停止(特に DELETE / UPDATE)
- DBA 緊急対応必須
- 単純な REBUILD では解決しない場合が多い
このエラーの本質は、Rizwan’s Oracle Blog が明確に述べています:
「インデックスに格納されたキーと、テーブルに格納された値の間に
ミスマッチが発生している状態」
- 1. 結論:REBUILD ONLINE or DROP + CREATE
- 2. Oracle インデックスの構造
- 3. 【原因①】Oracle 内部バグ(最多)
- 4. 【原因②】パラレル DML 中の corruption
- 5. 【原因③】ストレージ障害
- 6. 【原因④】システムクラッシュ中の DML
- 7. 【原因⑤】Function-Based Index の関数変更
- 8. 【原因⑥】グローバル/ローカルインデックス整合性
- 9. 【原因⑦】SAP BI アップグレード(実例)
- 10. 【原因⑧】パーティションメンテナンス中
- 11. 【原因⑨】Multi-user 同時 DML
- 12. 【原因⑩】Data Pump インポート後
- 13. 診断ツール完全リファレンス
- 14. 6つの解決策 完全リファレンス
- 15. Rails / Java / Python 対応
- 16. 実践シナリオ
- 17. トラブルシューティング
- 18. よくある質問(FAQ)
- 18.1. Q1. REBUILD (OFFLINE) が効かない理由
- 18.2. Q2. DROP + CREATE のリスク
- 18.3. Q3. ALTER TABLE MOVE の効果
- 18.4. Q4. ANALYZE VALIDATE STRUCTURE の副作用
- 18.5. Q5. Function-Based Index の問題
- 18.6. Q6. Rails での対応
- 18.7. Q7. Java での対応
- 18.8. Q8. Python での対応
- 18.9. Q9. パフォーマンス影響
- 18.10. Q10. Oracle Support への報告
- 18.11. Q11. 予防策
- 18.12. Q12. Autonomous DB での挙動
- 19. 参考リンク
- 20. まとめ
エラーメッセージの詳細
Oracle 10g+:
ORA-08102: index key not found, obj# 7941, file 11, block 398468 (2)
obj# file block
対象インデックス オブジェクト
obj# から破損オブジェクト特定:
SELECT owner, object_name, object_type
FROM dba_objects
WHERE object_id = 7941;
REBUILD ONLINE vs OFFLINE の重大な違い
日本語圏でほぼ知られていない重要な事実:
ALTER INDEX ... REBUILD (OFFLINE):
→ 既存インデックスから新インデックスを構築
→ 破損キーもそのままコピー → 治らない!
ALTER INDEX ... REBUILD ONLINE:
→ テーブルから直接読み取って新インデックス構築
→ 破損キーが正しく修復
→ 多くの場合これで解決
DROP + CREATE INDEX:
→ 完全新規作成
→ 最も確実な解決方法
Rizwan の実例:
1. REBUILD (OFFLINE) 試行 → 失敗
2. DROP + CREATE INDEX → 成功
Mohamed Houri の実例:
1. REBUILD (OFFLINE) 試行 → 失敗
2. ALTER TABLE MOVE → 全インデックス UNUSABLE
3. REBUILD 実行 → 成功
(UNUSABLE 状態からの REBUILD はテーブルから読み取り)
現場で最も典型的なパターン:
- Oracle 内部バグ(多数の既知バグ)
- パラレル DML 中の corruption
- ストレージ障害(RAID、SAN、NAS)
- システムクラッシュ中の DML
- Function-Based Index の関数変更後
- グローバル/ローカルインデックスの整合性問題(パーティション操作)
- SAP BI アップグレード中(実例多数)
- パーティションメンテナンス中
- Multi-user 同時 DML での競合
- Data Pump インポート後
さらに、併発する典型的なエラー:
ORA-00604: error occurred at recursive SQL level 1
ORA-08102: index key not found, obj# 246739, file 68, block 78323 (2)
recursive SQL レベルでの発生も多く、内部処理が影響を受けます。
多くの日本語記事が「REBUILD せよ」で終わりますが、実務では:
- REBUILD の 3 モード(OFFLINE / ONLINE / UNUSABLE→REBUILD)の厳密な違い
ANALYZE INDEX ... VALIDATE STRUCTUREによる事前診断INDEX_STATSビュー活用DBVERIFY (dbv)による物理破損チェック- Function-Based Index の関数不変性違反
- グローバルインデックスのパーティション操作影響
- SAP
brtoolsによる対処 - Rails ヘルスチェックでの予防
ALTER TABLE MOVEによる強制的な整合性回復- リカバリからの復元(最終手段)
さらに、Oracle のマルチバージョンでの対応:
9i or Earlier: ORA-08102: index key not found, obj# %s, dba %s (%s)
10g+: ORA-08102: index key not found, obj# %s, file %s, block %s (%s)
本記事では、ORA-08102: index key not found の完全な原因と解決方法を、リファレンスとして実用的に整理します。REBUILD の罠、10大発生パターン、6つの解決策、SAP 対応、Rails/Java/Python 対応、実践シナリオ、FAQまで完全網羅。この1本で ORA-08102 に冷静に的確に対処できるようになります。
結論:REBUILD ONLINE or DROP + CREATE
時間がない方向けに、最速の対処を先に示します。
エラーメッセージの読み方
ORA-08102: index key not found, obj# 7941, file 11, block 398468 (2)
obj# file block
↑ ↑ ↑
破損オブジェクト データファイル ブロック
= インデックスに存在すべきキーが物理的に欠落
テーブル-インデックス不整合
最速の対処手順
-- STEP 1: obj# から破損オブジェクト特定
SELECT owner, object_name, object_type
FROM dba_objects
WHERE object_id = <obj#>;
-- STEP 2: REBUILD ONLINE 試行(テーブルから再構築)
ALTER INDEX schema.index_name REBUILD ONLINE;
-- STEP 3: 失敗なら UNUSABLE + REBUILD
ALTER INDEX schema.index_name UNUSABLE;
ALTER INDEX schema.index_name REBUILD;
-- STEP 4: 最終手段: DROP + CREATE
-- DDL 取得
SELECT DBMS_METADATA.GET_DDL('INDEX', 'INDEX_NAME', 'OWNER')
FROM dual;
-- DROP + CREATE
DROP INDEX schema.index_name;
CREATE INDEX ...;
6つの解決策
| # | 手法 | 使う場面 |
|---|---|---|
| ① | REBUILD ONLINE | 第一選択 |
| ② | UNUSABLE + REBUILD | ONLINE 失敗時 |
| ③ | DROP + CREATE | 最も確実 |
| ④ | ALTER TABLE MOVE | 全 index リビルド |
| ⑤ | ANALYZE VALIDATE | 診断 |
| ⑥ | DBVERIFY | 物理チェック |
REBUILD の 3 モード
OFFLINE REBUILD:
既存インデックス → 新インデックス
破損コピー、治らない
ONLINE REBUILD:
テーブル → 新インデックス
破損修復可能
UNUSABLE → REBUILD:
UNUSABLE 状態から
必ずテーブルから再構築
破損修復可能
詳細は以下で解説します。
Oracle インデックスの構造
インデックスの物理構造
インデックスセグメント
├── ルートブロック
├── ブランチブロック
├── リーフブロック
│ ├── キー値 → ROWID (テーブル位置)
│ └── 順序付き
インデックス-テーブル整合性
通常状態:
インデックスキー ↔ テーブル値
1:1 対応
Oracle が DML で自動維持
ORA-08102 状態:
インデックスに登録されるべきキー欠落
または
テーブル値とインデックスキーの不一致
→ Oracle が矛盾を検出
→ ORA-08102 発生
破損の種類
論理的破損(本記事の主対象):
- キーの欠落
- キー-値の不一致
- 通常 REBUILD ONLINE / DROP + CREATE で修復
物理的破損(別問題):
- ブロック corruption
- ORA-01578 発生
- DBVERIFY / RMAN BLOCKRECOVER で対処
【原因①】Oracle 内部バグ(最多)
症状
本番運用中に突然発生
特定の DML(DELETE 等)で ORA-08102
再現条件が不明瞭
対処
A. Oracle Support 案件化 + パッチ確認:
- MOS で類似バグ検索
- 該当バグの patch 適用
- 最新 PSU / CPU 適用
B. 応急処置: DROP + CREATE:
DROP INDEX schema.idx_name;
CREATE INDEX schema.idx_name ON tab(col);
内部エラーは ORA-00600: internal error の記事も参照してください。
【原因②】パラレル DML 中の corruption
シナリオ
ALTER SESSION ENABLE PARALLEL DML;
DELETE /*+ PARALLEL(orders 8) */ FROM orders
WHERE order_date < DATE '2020-01-01';
-- パラレル実行中のインデックスメンテナンス競合
-- → 稀に corruption
対処
REBUILD ONLINE + パラレル度制限:
-- パラレル DML 無効化
ALTER SESSION DISABLE PARALLEL DML;
-- インデックス REBUILD
ALTER INDEX orders_idx REBUILD ONLINE;
【原因③】ストレージ障害
シナリオ
alert.log:
"I/O error on file 11 block 398468"
その後
"ORA-08102: index key not found, obj# 7941, file 11, block 398468"
診断
A. OS レベル確認:
$ dmesg | grep -E "(I/O error|read error)"
$ smartctl -a /dev/sda
B. RMAN BLOCKRECOVER:
rman target /
RMAN> BACKUP VALIDATE DATAFILE 11;
RMAN> RECOVER DATAFILE 11 BLOCK 398468;
C. インデックス再作成:
DROP INDEX schema.idx_name;
CREATE INDEX schema.idx_name ON tab(col);
破損関連は ORA-01578: data block corrupted の記事、ORA-00376: file cannot be read の記事も参照してください。
【原因④】システムクラッシュ中の DML
シナリオ
1. 大量 DML 実行中
2. 電源断 or OS クラッシュ
3. 再起動後
4. Instance Recovery 実行
5. 稀に index 不整合残存
6. → ORA-08102
対処
REBUILD ONLINE:
ALTER INDEX schema.idx_name REBUILD ONLINE;
失敗なら DROP + CREATE。
【原因⑤】Function-Based Index の関数変更
シナリオ
-- 関数を使ったインデックス
CREATE INDEX idx_upper ON emp (UPPER(name));
-- カスタム関数
CREATE FUNCTION my_upper(v VARCHAR2) RETURN VARCHAR2
DETERMINISTIC AS
BEGIN
RETURN UPPER(v);
END;
/
CREATE INDEX idx_myupper ON emp (my_upper(name));
-- 関数を変更(DETERMINISTIC 違反)
CREATE OR REPLACE FUNCTION my_upper(v VARCHAR2) RETURN VARCHAR2
DETERMINISTIC AS
BEGIN
RETURN LOWER(v); -- ⚠️ 別の結果!
END;
/
-- インデックス不整合
-- → ORA-08102
対処
関数のロジックを元に戻す or インデックス再作成:
DROP INDEX idx_myupper;
CREATE INDEX idx_myupper ON emp (my_upper(name));
【原因⑥】グローバル/ローカルインデックス整合性
シナリオ(実例)
-- ローカルインデックス操作
ALTER TABLE ENTITY_ALT_IDENTIFIER
MODIFY PARTITION P_59221_1000_DL UNUSABLE LOCAL INDEXES;
-- INSERT
INSERT INTO ENTITY_ALT_IDENTIFIER VALUES (...);
-- ローカルインデックス REBUILD
ALTER TABLE ENTITY_ALT_IDENTIFIER
MODIFY PARTITION P_59221_1000_DL REBUILD UNUSABLE LOCAL INDEXES;
-- TRUNCATE + UPDATE INDEXES
ALTER TABLE ENTITY_ALT_IDENTIFIER
TRUNCATE PARTITION P_59221_1000_DL UPDATE INDEXES;
-- グローバル INDEX も UNUSABLE に
-- → 通常業務で ORA-08102
解決
-- グローバル INDEX を明示的に REBUILD
ALTER INDEX IDX_ENTITY_ALT_IDEN_PKEY REBUILD ONLINE;
インデックス関連は ORA-01502: index unusable の記事、ORA-14400: inserted partition key does not map の記事も参照してください。
【原因⑦】SAP BI アップグレード(実例)
症状(実例)
SAP BI 3.5 → BI 7.0 アップグレード中
TABIM_UPG フェーズで ORA-08102
対処(SAP 公式)
A. brtools 使用:
brtools -> 3. Segment management -> 2. Rebuild indexes -> 7. Index name -> continue
B. インデックス REBUILD:
ALTER INDEX <index_name> REBUILD ONLINE;
C. 全インデックス再構築:
SELECT 'ALTER INDEX ' || index_name || ' REBUILD ONLINE;'
FROM user_indexes
WHERE table_name IN ('AFFECTED_TABLE');
【原因⑧】パーティションメンテナンス中
シナリオ
-- パーティション DDL 中断
ALTER TABLE orders EXCHANGE PARTITION p_2024 WITH TABLE archive_2024;
-- 何らかの理由で失敗
-- グローバル/ローカル INDEX 不整合
-- → ORA-08102
解決
UPDATE INDEXES 付き実行:
ALTER TABLE orders EXCHANGE PARTITION p_2024 WITH TABLE archive_2024
UPDATE INDEXES;
失敗時: 全 INDEX REBUILD:
BEGIN
FOR r IN (SELECT index_name FROM user_indexes
WHERE table_name = 'ORDERS' AND status IN ('UNUSABLE', 'INVALID')) LOOP
EXECUTE IMMEDIATE
'ALTER INDEX ' || r.index_name || ' REBUILD ONLINE';
END LOOP;
END;
/
【原因⑨】Multi-user 同時 DML
シナリオ
複数セッションが同じインデックスに対して DML 実行
稀な競合状態
→ index-table 不整合
→ ORA-08102
対処
A. インデックス REBUILD ONLINE:
ALTER INDEX schema.idx_name REBUILD ONLINE;
B. アプリ側で serialization 検討。
【原因⑩】Data Pump インポート後
シナリオ
$ impdp scott/tiger dumpfile=orders.dmp
-- インポート成功
-- 業務で ORA-08102
対処
インポート後の全 INDEX 検証・REBUILD:
-- INDEX 検証
BEGIN
FOR r IN (SELECT index_name FROM user_indexes) LOOP
BEGIN
EXECUTE IMMEDIATE
'ANALYZE INDEX ' || r.index_name || ' VALIDATE STRUCTURE';
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Corrupt: ' || r.index_name);
END;
END LOOP;
END;
/
Data Pump 関連は Oracle Data Pump 使い方の記事も参照してください。
診断ツール完全リファレンス
obj# から特定
SELECT owner, object_name, object_type, status
FROM dba_objects
WHERE object_id = <obj#>;
file / block からセグメント特定
SELECT owner, segment_name, segment_type, tablespace_name
FROM dba_extents
WHERE file_id = <file>
AND <block> BETWEEN block_id AND block_id + blocks - 1;
ANALYZE INDEX VALIDATE STRUCTURE
-- インデックス構造検証
ANALYZE INDEX schema.idx_name VALIDATE STRUCTURE;
-- 結果は INDEX_STATS に
SELECT height, blocks, name, del_lf_rows_len, distinct_keys
FROM index_stats;
INDEX_STATS
-- ANALYZE 実行後、単一行
SELECT * FROM index_stats;
DBVERIFY (dbv)
# データファイルの物理チェック
$ dbv file=/u01/oradata/orcl/users01.dbf blocksize=8192
# 出力
Total Pages Examined : XXX
Total Pages Processed (Data) : XXX
Total Pages Failing (Data) : 0 ← 0 なら OK
Total Pages Marked Corrupt : 0
V$DATABASE_BLOCK_CORRUPTION
-- ブロック破損一覧
SELECT * FROM v$database_block_corruption;
DDL 取得
SET LONG 999999
SELECT DBMS_METADATA.GET_DDL('INDEX', 'IDX_NAME', 'SCHEMA')
FROM dual;
6つの解決策 完全リファレンス
解決策① ALTER INDEX REBUILD ONLINE(第一選択)
-- テーブルから直接読み取って再構築
ALTER INDEX schema.idx_name REBUILD ONLINE;
-- 並列 + ONLINE
ALTER INDEX schema.idx_name REBUILD ONLINE PARALLEL 4;
メリット:
- テーブルから読み取るため破損修復可能
- 業務停止不要
注意:
- 若干の負荷 + 一時領域増加
解決策② UNUSABLE + REBUILD
-- STEP 1: UNUSABLE 化
ALTER INDEX schema.idx_name UNUSABLE;
-- STEP 2: REBUILD(テーブルから)
ALTER INDEX schema.idx_name REBUILD;
なぜ効くか:
- UNUSABLE 状態からの REBUILD はテーブルから読み取り
- 通常の OFFLINE REBUILD と異なる挙動
- ONLINE と同等の修復効果
解決策③ DROP + CREATE(最も確実)
-- STEP 1: DDL 取得
SET LONG 999999
SELECT DBMS_METADATA.GET_DDL('INDEX', 'IDX_NAME', 'SCHEMA') FROM dual;
-- STEP 2: DROP
DROP INDEX schema.idx_name;
-- STEP 3: CREATE
CREATE INDEX schema.idx_name ON tab(col);
-- または元の DDL で再作成
最も確実だが:
- 一時的にインデックスなし
- SELECT パフォーマンス激低下
- PRIMARY KEY / UNIQUE 制約の場合は制約先に DROP
解決策④ ALTER TABLE MOVE(全インデックス影響)
-- テーブル MOVE で全インデックス UNUSABLE
ALTER TABLE schema.tab_name MOVE;
-- 全インデックス REBUILD
BEGIN
FOR r IN (SELECT index_name FROM user_indexes
WHERE table_name = 'TAB_NAME'
AND status = 'UNUSABLE') LOOP
EXECUTE IMMEDIATE
'ALTER INDEX ' || r.index_name || ' REBUILD ONLINE';
END LOOP;
END;
/
メリット: 一発で全インデックス修復。 注意: テーブルサイズ大きいと時間かかる。
解決策⑤ ANALYZE INDEX VALIDATE STRUCTURE(診断)
-- 破損検出
ANALYZE INDEX schema.idx_name VALIDATE STRUCTURE;
-- エラー発生なら破損確定
-- 全インデックス検証
BEGIN
FOR r IN (SELECT index_name FROM user_indexes) LOOP
BEGIN
EXECUTE IMMEDIATE
'ANALYZE INDEX ' || r.index_name || ' VALIDATE STRUCTURE';
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Corrupt: ' || r.index_name || ' - ' || SQLERRM);
END;
END LOOP;
END;
/
解決策⑥ DBVERIFY(物理チェック)
# データファイルの物理破損チェック
$ dbv file=/u01/oradata/orcl/users01.dbf blocksize=8192
# インデックスのあるデータファイル特定
-- インデックスの datafile 特定
SELECT DISTINCT file_id FROM dba_extents
WHERE segment_name = 'IDX_NAME'
AND owner = 'SCHEMA';
Rails / Java / Python 対応
Rails ActiveRecord
エラーハンドリング:
begin
Order.where(id: 12345).destroy_all
rescue ActiveRecord::StatementInvalid => e
if e.message.include?("ORA-08102")
Rails.logger.fatal "Index corruption: #{e.message}"
NotifyOps.critical("DBA action required - index rebuild")
# 自動修復スクリプト起動 or 手動対応
end
end
マイグレーション後の検証:
class VerifyIndexes < ActiveRecord::Migration[8.0]
def up
execute <<-SQL
BEGIN
FOR r IN (SELECT index_name FROM user_indexes) LOOP
BEGIN
EXECUTE IMMEDIATE
'ANALYZE INDEX ' || r.index_name || ' VALIDATE STRUCTURE';
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20001,
'Corrupt index: ' || r.index_name);
END;
END LOOP;
END;
SQL
end
end
Rails 8 系の詳細は Rails 8 アップグレードガイドの記事も参照してください。
Java (JDBC)
try {
ps.executeUpdate();
} catch (SQLException e) {
if (e.getErrorCode() == 8102) {
logger.fatal("Index corruption: " + e.getMessage());
alertingService.critical("DBA action required");
// obj# 抽出
Pattern p = Pattern.compile("obj# (\\d+)");
Matcher m = p.matcher(e.getMessage());
if (m.find()) {
logger.error("Corrupt object ID: " + m.group(1));
}
}
}
Python (oracledb)
import oracledb
import re
import logging
try:
cursor.execute(sql, params)
except oracledb.DatabaseError as e:
error_obj, = e.args
if error_obj.code == 8102:
# obj#, file, block 抽出
match = re.search(
r'obj# (\d+), file (\d+), block (\d+)',
error_obj.message
)
if match:
obj_id, file_id, block_id = match.groups()
logging.critical(
f"Index corrupt: obj#{obj_id}, file{file_id}, block{block_id}"
)
実践シナリオ
シナリオ1:本番緊急対応
-- 1. エラー詳細取得
-- ORA-08102: index key not found, obj# 7941, file 11, block 398468 (2)
-- 2. obj# から特定
SELECT owner, object_name, object_type
FROM dba_objects WHERE object_id = 7941;
-- APP.ORDERS_IDX (INDEX)
-- 3. REBUILD ONLINE 試行
ALTER INDEX APP.ORDERS_IDX REBUILD ONLINE;
-- 4. 失敗なら UNUSABLE + REBUILD
ALTER INDEX APP.ORDERS_IDX UNUSABLE;
ALTER INDEX APP.ORDERS_IDX REBUILD;
-- 5. さらに失敗なら DROP + CREATE
SELECT DBMS_METADATA.GET_DDL('INDEX', 'ORDERS_IDX', 'APP') FROM dual;
DROP INDEX APP.ORDERS_IDX;
CREATE INDEX APP.ORDERS_IDX ON APP.ORDERS(order_id);
-- 6. 動作確認
DELETE FROM APP.ORDERS WHERE id = 12345;
シナリオ2:全インデックス検証
-- 定期メンテナンス
BEGIN
FOR r IN (SELECT owner, index_name FROM dba_indexes
WHERE owner = 'APP') LOOP
BEGIN
EXECUTE IMMEDIATE
'ANALYZE INDEX ' || r.owner || '.' || r.index_name ||
' VALIDATE STRUCTURE';
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('CORRUPT: ' || r.owner || '.' || r.index_name);
END;
END LOOP;
END;
/
シナリオ3:SAP BI アップグレード対応
# brtools 使用
brtools
# メニュー:
# 3. Segment management
# 2. Rebuild indexes
# 7. Index name
# [対象インデックス名]
# continue
または SQL 直接:
-- 影響テーブル特定(TP trace から)
-- 該当テーブルの全インデックス REBUILD
BEGIN
FOR r IN (SELECT index_name FROM user_indexes
WHERE table_name = 'AFFECTED_TABLE') LOOP
EXECUTE IMMEDIATE
'ALTER INDEX ' || r.index_name || ' REBUILD ONLINE';
END LOOP;
END;
/
シナリオ4:CI/CD デプロイ後の検証
- name: Post-deploy index validation
run: |
sqlplus -s $DB_USER/$DB_PW <<EOF
WHENEVER SQLERROR EXIT SQL.SQLCODE
DECLARE
v_corrupt NUMBER := 0;
BEGIN
FOR r IN (SELECT index_name FROM user_indexes
WHERE status = 'VALID') LOOP
BEGIN
EXECUTE IMMEDIATE
'ANALYZE INDEX ' || r.index_name || ' VALIDATE STRUCTURE';
EXCEPTION
WHEN OTHERS THEN
v_corrupt := v_corrupt + 1;
END;
END LOOP;
IF v_corrupt > 0 THEN
RAISE_APPLICATION_ERROR(-20001, 'Corrupt indexes: ' || v_corrupt);
END IF;
END;
/
EOF
Kamal 2 デプロイの詳細は Kamal 2 デプロイの記事を参照してください。
シナリオ5:Docker Oracle でのテスト
docker exec -it oracle-xe sqlplus scott/tiger <<EOF
CREATE TABLE t (id NUMBER PRIMARY KEY, val VARCHAR2(100));
INSERT INTO t VALUES (1, 'test1');
INSERT INTO t VALUES (2, 'test2');
COMMIT;
-- 通常はエラーなし
SELECT * FROM t WHERE id = 1;
DELETE FROM t WHERE id = 1;
-- ANALYZE で検証
ANALYZE INDEX SYS_C0011234 VALIDATE STRUCTURE;
SELECT height, blocks FROM index_stats;
EOF
Docker 関連は docker daemon 接続エラーの記事、Docker no space left on device の記事も参照してください。
シナリオ6:Function-Based Index の再作成
-- 関数変更検出
ALTER INDEX idx_myupper INVISIBLE;
-- 状態確認(VALIDATE でも検出できない場合あり)
DROP INDEX idx_myupper;
CREATE INDEX idx_myupper ON emp (my_upper(name));
-- INVISIBLE 解除
-- 実際は DROP CREATE で新規、INVISIBLE は不要
シナリオ7:ALTER TABLE MOVE パターン
-- 1. 全インデックス確認
SELECT index_name, status FROM user_indexes
WHERE table_name = 'ORDERS';
-- 2. テーブル MOVE
ALTER TABLE orders MOVE;
-- 3. 全インデックス UNUSABLE 化
SELECT index_name, status FROM user_indexes
WHERE table_name = 'ORDERS';
-- 全て UNUSABLE
-- 4. 全 REBUILD
BEGIN
FOR r IN (SELECT index_name FROM user_indexes
WHERE table_name = 'ORDERS' AND status = 'UNUSABLE') LOOP
EXECUTE IMMEDIATE
'ALTER INDEX ' || r.index_name || ' REBUILD ONLINE';
END LOOP;
END;
/
インデックス関連は ORA-01502: index unusable の記事も参照してください。
シナリオ8:Python 監視スクリプト
import oracledb
import logging
def validate_all_indexes(cursor, owner):
cursor.execute("""
SELECT index_name FROM dba_indexes
WHERE owner = :1 AND status = 'VALID'
""", [owner.upper()])
indexes = cursor.fetchall()
corrupt = []
for (idx_name,) in indexes:
try:
cursor.execute(
f"ANALYZE INDEX {owner}.{idx_name} VALIDATE STRUCTURE"
)
except oracledb.DatabaseError as e:
error_obj, = e.args
corrupt.append({
'name': idx_name,
'error': error_obj.message
})
logging.error(f"Corrupt: {idx_name}")
return corrupt
シナリオ9:Rails ヘルスチェック
class IndexHealthController < ApplicationController
def check
corrupt = []
ActiveRecord::Base.connection.execute(<<-SQL).each do |row|
SELECT index_name FROM user_indexes WHERE status = 'VALID'
SQL
idx_name = row['index_name']
begin
ActiveRecord::Base.connection.execute(
"ANALYZE INDEX #{idx_name} VALIDATE STRUCTURE"
)
rescue ActiveRecord::StatementInvalid
corrupt << idx_name
end
end
if corrupt.any?
render json: { status: 'CRITICAL', corrupt_indexes: corrupt },
status: 503
else
render json: { status: 'OK' }
end
end
end
シナリオ10:Autonomous DB
Autonomous DB では:
- 自動メンテナンスあり
- 通常 ORA-08102 稀
- 発生時は OCI Console でチケット
- 手動 REBUILD も可能
トラブルシューティング
REBUILD ONLINE 失敗
UNUSABLE + REBUILD、または DROP + CREATE。
DROP INDEX で PRIMARY KEY エラー
制約先に DROP:
ALTER TABLE tab DROP CONSTRAINT pk_name;
CREATE UNIQUE INDEX pk_name ON tab(col);
ALTER TABLE tab ADD CONSTRAINT pk_name PRIMARY KEY (col)
USING INDEX pk_name;
ANALYZE VALIDATE STRUCTURE でエラー
破損確定、REBUILD ONLINE or DROP + CREATE。
頻繁に発生
Oracle Support 案件化、パッチ確認、ストレージ検査。
バックアップから復元検討
深刻な破損 + バックアップあり → RMAN で該当データファイル復元。
PostgreSQL からの移行
PG は REINDEX、Oracle は ALTER INDEX REBUILD + オンライン差。
よくある質問(FAQ)
Q1. REBUILD (OFFLINE) が効かない理由
既存インデックスから再構築、破損もコピー。ONLINE or UNUSABLE + REBUILD で解決。
Q2. DROP + CREATE のリスク
一時的にインデックスなし、SELECT 激低下、制約先処理必要。
Q3. ALTER TABLE MOVE の効果
全インデックス UNUSABLE、REBUILD で修復。
Q4. ANALYZE VALIDATE STRUCTURE の副作用
排他ロック、業務中は要注意。
Q5. Function-Based Index の問題
関数 DETERMINISTIC 違反、DROP + CREATE 必須。
Q6. Rails での対応
エラー検出 + DBA 通知、自動化スクリプト。
Q7. Java での対応
errorCode == 8102 検出、監視統合。
Q8. Python での対応
oracledb.DatabaseError.code == 8102 + obj#/file/block 抽出。
Q9. パフォーマンス影響
業務停止級、DML 完全停止。
Q10. Oracle Support への報告
MOS チケット、パッチ確認、バグ番号追跡。
Q11. 予防策
- 定期 ANALYZE VALIDATE
- パッチ適用
- ストレージ監視
- 監視スクリプト
Q12. Autonomous DB での挙動
自動メンテナンスあり、稀に発生。
参考リンク
Oracle 公式
- Oracle Database Error Messages: ORA-08102
- Oracle Database SQL Language Reference: ALTER INDEX
- Oracle Database Administrator’s Guide: Managing Indexes
- DBVERIFY Utility
まとめ
ORA-08102: index key not found の要点を再整理します。
エラーの本質
インデックスに登録されるべきキーが物理的に欠落
→ テーブル-インデックス不整合
→ DML 全停止
→ DBA 緊急対応
→ REBUILD ONLINE / DROP CREATE で修復
エラーメッセージの読み方
ORA-08102: index key not found, obj# 7941, file 11, block 398468 (2)
obj# file block
↑ ↑ ↑
破損オブジェクト データファイル ブロック
REBUILD の 3 モード
| モード | 動作 | 修復効果 |
|---|---|---|
| REBUILD (OFFLINE) | 既存 index から | 効かない |
| REBUILD ONLINE | テーブルから | 修復可能 |
| UNUSABLE + REBUILD | テーブルから | 修復可能 |
10大原因
| # | 原因 | 対処 |
|---|---|---|
| ① | Oracle 内部バグ | Support + パッチ |
| ② | パラレル DML | ONLINE REBUILD |
| ③ | ストレージ障害 | HW 検査 + REBUILD |
| ④ | システムクラッシュ | REBUILD ONLINE |
| ⑤ | Function-Based | DROP + CREATE |
| ⑥ | パーティション整合性 | UPDATE INDEXES |
| ⑦ | SAP BI アップグレード | brtools / REBUILD |
| ⑧ | パーティションメンテ | UPDATE INDEXES |
| ⑨ | Multi-user 同時 DML | ONLINE REBUILD |
| ⑩ | Data Pump 後 | VALIDATE + REBUILD |
6つの解決策
-- ① REBUILD ONLINE(第一選択)
ALTER INDEX idx_name REBUILD ONLINE;
-- ② UNUSABLE + REBUILD
ALTER INDEX idx_name UNUSABLE;
ALTER INDEX idx_name REBUILD;
-- ③ DROP + CREATE(最も確実)
DROP INDEX idx_name;
CREATE INDEX idx_name ON tab(col);
-- ④ ALTER TABLE MOVE
ALTER TABLE tab MOVE;
-- 全 index UNUSABLE → REBUILD
-- ⑤ ANALYZE VALIDATE
ANALYZE INDEX idx_name VALIDATE STRUCTURE;
-- ⑥ DBVERIFY
$ dbv file=/path/to/datafile.dbf
診断コマンド Top 5
-- ① obj# から特定
SELECT owner, object_name FROM dba_objects WHERE object_id = <obj#>;
-- ② file/block からセグメント
SELECT segment_name FROM dba_extents
WHERE file_id = <f> AND <b> BETWEEN block_id AND block_id + blocks - 1;
-- ③ ANALYZE 検証
ANALYZE INDEX idx VALIDATE STRUCTURE;
-- ④ INDEX_STATS
SELECT * FROM index_stats;
-- ⑤ DBVERIFY (bash)
dbv file=/path blocksize=8192
各言語での対応
Rails: StatementInvalid + errorCode 8102、監視統合
Java: errorCode == 8102、obj# 抽出
Python: oracledb.DatabaseError.code == 8102、正規表現で詳細抽出
共通: DBA 即通知、自動修復スクリプト
予防のポイント
1. 定期 ANALYZE INDEX VALIDATE STRUCTURE
2. Oracle パッチ定期適用
3. ストレージ監視(SMART/RAID)
4. UPS で電源保護
5. パーティション DDL は UPDATE INDEXES
6. Function-Based は DETERMINISTIC 遵守
7. パラレル DML 慎重運用
8. CI/CD で post-deploy 検証
9. Rails/Java/Python でヘルスチェック
10. Autonomous DB は自動メンテナンス活用
これらの知識は、Oracle DBA の本番運用・障害対応・データ整合性・Rails / Java / Python アプリ運用・SAP + Oracle 管理・CI/CD パイプライン・パーティション管理・監視設計・パッチ管理など、あらゆる場面で活用できます。本記事をブックマークしておけば、ORA-08102 に出会っても冷静に的確に対処できるようになります。
本記事は2026年6月時点の情報をもとに、Oracle Database 19c〜23ai での動作確認・公式ドキュメントに基づき作成しています。Oracle のバージョンにより挙動が異なる場合があるため、最新の情報は Oracle 公式ドキュメント(docs.oracle.com)もあわせてご確認ください。
-
前の記事
【完全ガイド】ORA-01502: index or partition of such index is in unusable state の原因と解決方法|Direct Path Insert・パーティション・REBUILD 徹底解説 2026.09.02
-
次の記事
【完全ガイド】ORA-01489: result of string concatenation is too long の原因と解決方法|LISTAGG 4000 バイト・ON OVERFLOW TRUNCATE 徹底解説 2026.09.04
コメントを書く