查unusable索引需分层检查:全局索引查dba_indexes.status,分区索引查dba_ind_partitions.status,子分区索引查dba_ind_subpartitions;unusable索引仍占空间且需精准重建并更新统计信息。

查UNUSABLE索引不能只看dba_indexes.status
很多人一查dba_indexes.status = 'UNUSABLE'没结果,就以为索引都正常——这是最大误区。全局索引失效确实会体现在dba_indexes里,但分区索引(LOCAL)的某个子分区失效时,主索引状态仍可能是VALID,真正挂掉的是dba_ind_partitions里的某一行。
必须分两层查:
- 全局/普通索引:用
SELECT index_name, status FROM dba_indexes WHERE status = 'UNUSABLE' - 分区索引:用
SELECT index_name, partition_name, status FROM dba_ind_partitions WHERE status = 'UNUSABLE' - 子分区索引(如有):加查
dba_ind_subpartitions,条件同上
注意:dba_*视图需DBA权限;普通用户可用user_indexes和user_ind_partitions,但只能看到自己拥有的对象。
UNUSABLE索引段还在表空间里占空间
UNUSABLE不等于“被删了”,它只是逻辑不可用,物理段仍在表空间中,持续占用空间,还可能阻塞ALTER TABLE MOVE等操作。想确认是否真有无效段,得联合查段信息:
SELECT s.owner, s.segment_name, s.segment_type, s.tablespace_name, o.status FROM dba_segments s JOIN dba_objects o ON s.owner = o.owner AND s.segment_name = o.object_name WHERE s.tablespace_name = 'YOUR_TS' AND o.status = 'UNUSABLE' AND o.object_type IN ('INDEX', 'INDEX PARTITION', 'INDEX SUBPARTITION')
替换YOUR_TS为实际表空间名,大小写敏感。漏掉object_type过滤会混入大量包、类型等干扰项。
重建命令要按索引类型精准匹配
重建不是一刀切。错用命令会报错或无效:
- 普通索引或全局索引:
ALTER INDEX idx_name REBUILD - 局部索引的某个分区:
ALTER INDEX idx_name REBUILD PARTITION part_name - 子分区索引:
ALTER INDEX idx_name REBUILD SUBPARTITION subpart_name - 想减少锁表时间:加
ONLINE(12c+支持),如REBUILD ONLINE - 指定表空间或并行度可提速:
REBUILD TABLESPACE ts_name PARALLEL 4
别用UPDATE GLOBAL INDEXES补救——它只在DROP PARTITION等DDL执行时起作用,对已发生的UNUSABLE完全无效。
批量修复脚本要避开权限和命名陷阱
DBA常用游标批量重建,但要注意两点:
- 普通用户无法执行
dba_*视图查询,也不能ALTER INDEX其他用户索引,脚本必须用DBA账号运行 - 索引名含特殊字符(如双引号、小写混合)时,拼接语句要加双引号:
'alter index "' || owner || '"."' || index_name || '" rebuild' - 避免重建系统索引或临时对象,加过滤条件:
AND o.object_type = 'INDEX'且排除以$结尾的隐式索引(如LIKE '%$$')
最易被忽略的是:重建后必须收集统计信息,否则优化器可能继续忽略该索引——尤其是分区索引,DBMS_STATS.GATHER_INDEX_STATS或全表重收集才可靠。











