Oracle ORA-14415:LOB 索引异常导致 DROP TABLE 失败的处理案例

故障现象

在 Oracle 数据库日常维护过程中,遇到一个比较特殊的问题:删除一张业务表时,Oracle 返回 ORA-14415,提示索引处于部分删除状态,要求先执行 DROP INDEX。

执行的 SQL 如下:

DROP TABLE app_user.test_table;

报错信息:

ORA-14415: index in partially dropped state, submit DROP INDEX

查询表上索引

-- 表上的 indexes
SELECT owner,
       index_name,
       index_type,
       table_owner,
       table_name,
       status
FROM   dba_indexes
WHERE  table_owner = 'APP_USER'
AND    table_name = 'TEST_TABLE'
ORDER BY index_name;


-- 表上列附属的lob indexes

SELECT i.owner,
       i.index_name,
       i.index_type,
       i.table_owner,
       i.table_name,
       i.status,
       i.domidx_status
FROM   dba_indexes i
WHERE  i.table_owner = 'xxxx'
AND    i.table_name = 'xxxxx'
ORDER BY i.index_name;

-- base table ind$

create table ind$                                             /* index table */
( obj#          number not null,                            /* object number */
  /* DO NOT CREATE INDEX ON DATAOBJ#  AS IT WILL BE UPDATED IN A SPACE
   * TRANSACTION DURING TRUNCATE */
  dataobj#      number,                          /* data layer object number */
  ts#           number not null,                        /* tablespace number */
  file#         number not null,               /* segment header file number */
  block#        number not null,              /* segment header block number */
  bo#           number not null,              /* object number of base table */
  indmethod#    number not null,    /* object # for cooperative index method */
  cols          number not null,                        /* number of columns */
  pctfree$      number not null, /* minimum free space percentage in a block */
  initrans      number not null,            /* initial number of transaction */
  maxtrans      number not null,            /* maximum number of transaction */
  pctthres$     number,           /* iot overflow threshold, null if not iot */
  type#         number not null,              /* what kind of index is this? */
                                                               /* normal : 1 */
                                                               /* bitmap : 2 */
                                                              /* cluster : 3 */
                                                            /* iot - top : 4 */
                                                         /* iot - nested : 5 */
                                                            /* secondary : 6 */
                                                                 /* ansi : 7 */
                                                                  /* lob : 8 */
                                             /* cooperative index method : 9 */
  flags         number not null,
                /* mutable flags: anything permanent should go into property */
                                                    /* unusable (dls) : 0x01 */
                                                    /* analyzed       : 0x02 */
                                                    /* no logging     : 0x04 */
                                    /* index is currently being built : 0x08 */
                                     /* index creation was incomplete : 0x10 */
                                           /* key compression enabled : 0x20 */
                                              /* user-specified stats : 0x40 */
                                            /* secondary index on IOT : 0x80 */
                                      /* index is being online built : 0x100 */
                                    /* index is being online rebuilt : 0x200 */
                                                /* index is disabled : 0x400 */
                                                     /* global stats : 0x800 */

select  * from ind$ where bo$=xxx   -- table object id

这个案例发现表上的索引已不存在,但是表的lob列上还有索引。

尝试直接删除问题列

随后尝试删除表中的 LOB 相关列:

ALTER TABLE app_user.test_table
  DROP COLUMN lob_col1;

仍然返回 ORA-14415。

这表明常规的列删除操作同样受到了异常索引状态的影响。

将相关列标记为 UNUSED

在确认相关列不再需要、且业务允许清理后,尝试使用 SET UNUSED COLUMN。

ALTER TABLE app_user.test_table
  SET UNUSED COLUMN lob_col1;

ALTER TABLE app_user.test_table
  SET UNUSED COLUMN lob_col2;

ALTER TABLE app_user.test_table
  SET UNUSED COLUMN lob_col3;

执行结果均为:

Table altered.

与直接执行 DROP COLUMN 不同,SET UNUSED COLUMN 主要是将列标记为不可再使用,而不是立即完成列数据的物理清理。

在本案例中,这些操作可以成功执行。

删除 UNUSED 列

随后执行:

ALTER TABLE app_user.test_table
  DROP UNUSED COLUMNS;

执行成功:

Table altered.

完成这一步后,之前标记为 UNUSED 的列被进一步清理,表的状态也发生了变化。

需要强调的是,DROP UNUSED COLUMNS 并不是一个通用的索引修复命令。本案例中它能够成功,是实际验证得到的处理结果,不能据此推断所有 ORA-14415 都能采用相同方法解决。

再次删除表

完成上述处理后,再次执行:

DROP TABLE app_user.test_table;

本案例中,表最终可以正常删除。至此,故障处理完成。

总结

当drop table 遇到ora-14415, 检查表上的索引与lob列上的索引,drop column无法绕过。set unused是一种方法。

这个案例的经验是:Oracle 表级 DDL 失败时,如果错误指向处于部分删除状态的索引,应优先检查索引及其关联的 LOB 元数据,而不是简单地将问题归结为表损坏。

另外,ORA-14415 描述的是索引的部分删除状态,并不等同于已经确认的物理索引损坏。准确识别异常对象,再选择合适的清理路径,才是这类故障处理的关键。

Leave a Comment