必须先执行ALTER INDEX ... MONITORING USAGE开启监控,否则v$object_usage无有效数据;USED='NO'不等于可删,需覆盖全业务周期、排除hint强制使用及动态SQL漏记,并确认回收站已清空、分区子段无残留。

查 v$object_usage 前必须先开启索引监控
没开监控就查 v$object_usage,结果全是空的或过期数据。监控不是默认开启的,得对每个目标索引显式执行:ALTER INDEX schema.index_name MONITORING USAGE;。监控启动后,USED 列才开始记录是否被优化器实际选用——注意:仅限 CBO 模式下走计划的真实使用,EXPLAIN PLAN 或硬解析失败不算。
常见错误是批量建完索引就直接查视图,忘了这一步。另外,监控状态不会跨实例重启保留,RAC 环境下需在所有节点分别开启。
v$object_usage 的 USED 为 NO 不代表绝对可删
即使 USED = 'NO',也要确认三点:
- 业务周期是否覆盖了所有场景?比如夜间批处理、月末结账、报表导出等低频但关键路径是否已跑完
- 该索引是否被应用层 hint 强制指定?这类用法不会触发
v$object_usage计数 - 是否存在未捕获的动态 SQL(如 JDBC 拼接)绕过了共享池计划缓存,导致监控漏记
建议至少保留一个完整业务大周期(含节假日)再评估,别只看工作日三天数据。
真正释放空间不能只删索引,还得清理段残留
执行 DROP INDEX 后,段不会立刻从 dba_segments 消失——它先进回收站,仍计入表空间占用。必须补上:PURGE INDEX schema.index_name; 或清空整个回收站:PURGE RECYCLEBIN;。
如果索引建在分区表上,还要检查 dba_ind_partitions,主索引 STATUS = 'VALID' 不代表所有子分区都可用;个别子分区可能 UNUSABLE 却没报错,这种残留段得单独 ALTER INDEX ... REBUILD PARTITION 或 DROP。
删之前用 dba_segments 验证空间收益
别凭感觉删。先算清楚这个索引占多少真实空间:
SELECT segment_name, segment_type, ROUND(bytes/1024/1024/1024, 2) AS gb FROM dba_segments WHERE owner = 'SCHEMA_NAME' AND segment_name = 'INDEX_NAME';
再对比同 schema 下其他索引大小。如果目标索引才几 MB,而重建成本高(比如涉及大表锁)、或依赖它的物化视图日志还在,那省下的空间可能不值得动。
特别注意:LOBINDEX 和 IOT 的 overflow segment 也属于索引段,但名字不带 INDEX,容易被漏掉——查 segment_type IN ('INDEX', 'LOBINDEX', 'IOT_OVERFLOW') 更全。
真正卡住释放效果的,往往是回收站没清、分区子段残留、或者误判了“未使用”——监控窗口太短、hint 绕过、批处理脚本没跑全。这些点不核对清楚,删了索引空间也回不来。











