直接查 user_indexes 表中 status = 'UNUSABLE' 的全局索引(index_type = 'NORMAL'),修复需先执行 ALTER INDEX ... UNUSABLE 再 REBUILD;预防 DROP 分区失效须显式加 UPDATE GLOBAL INDEXES 子句。

查哪些全局索引已经 unusable
别靠猜,直接查 user_indexes。失效的全局索引不会报错、不写日志,状态字段就是唯一线索:
SELECT index_name, status, index_type FROM user_indexes WHERE table_name = 'YOUR_TABLE' AND index_type = 'NORMAL';
status = 'UNUSABLE' 就是它了。funcidx_status 是函数索引相关字段,和分区无关,不用管。
注意:本地索引(index_type = 'DOMAIN' 或查 user_ind_partitions)不受影响,只盯 user_indexes 里的全局索引。
修复已变成 unusable 的全局索引
不能直接 ALTER INDEX ... REBUILD —— 某些 Oracle 版本会报 ORA-01408(误导性错误),尤其当索引当前已是 UNUSABLE 状态时。
必须分两步走,控制明确、风险最低:
- 先快速置为不可用:
ALTER INDEX idx_name UNUSABLE;—— 这步毫秒级,几乎不阻塞 DML - 再重建:
ALTER INDEX idx_name REBUILD TABLESPACE ts_name PARALLEL 4;—— 加LOGGING和PARALLEL可提速,加ONLINE仅对本地索引有效,全局索引不支持在线重建
切记:UPDATE GLOBAL INDEXES 是 DDL 选项,不是修复命令,对已发生的 UNUSABLE 完全无效。
下次 DROP PARTITION 时怎么避免
预防的关键是显式加 UPDATE GLOBAL INDEXES 子句,但它只在特定 DDL 中生效,且语法位置敏感:
- 仅对
DROP、EXCHANGE、SPLIT、MERGE、MOVE、TRUNCATE分区操作有效;ADD和RENAME不支持 - 必须紧接主语句后、分号前,中间不能有换行或注释,否则被忽略
- 示例正确写法:
ALTER TABLE sales DROP PARTITION p_202201 UPDATE GLOBAL INDEXES; - 如果表有多个全局索引,该子句会一并维护;任一失败(如空间不足),整个 DDL 回滚
加了这句,索引全程保持 VALID,但耗时更长、锁持有时间增加,需权衡业务窗口。
为什么 DROP 后索引立刻 unusable 却不报错
Oracle 不是忘了清理,而是主动选择“宁可停用,也不返回错误结果”。因为全局索引是 B-tree 结构,跨分区条目无法局部验证有效性,删掉一个分区后,索引里仍存着指向它的键值 —— 若继续用,可能返回脏数据或漏数据。
所以它执行完 ALTER TABLE ... DROP PARTITION,就立即把全局索引状态设为 UNUSABLE,且不抛异常、不写 alert 日志,极易被忽略。
真正麻烦的不是修复动作本身,而是这个“静默失效”:等应用报 ORA-01502 才发现,往往已卡住写入或查询。日常巡检必须包含 user_indexes.status 查询,不能只依赖告警。











