做REBUILD ONLINE的时候可能会很慢,会有人强制杀掉会话, 不小心就会碰上ORA-8104的错误。

由于在做索引在线重建的时候,可能相关的表还在增删改,Oracle需要记录这个索引的相关变化,会创建一张临时表SYS_JOURNAL_<INDEX的OBJECT_ID> (IOT索引组织表) 来记录这些变化,最后进行merge。等索引重建完成后再删除这张临时表,REBUILD ONLINE刚刚开始的时候就会去创建这张日志表。如果REBUILD ONLINE被中途杀掉了,那么这张表和IND$中的FLAGS不会被自动清除,必须由SMON来清除。再重新rebuild online 时发现这张表已经存在了,就可能会报ORA-8104,并无法继续做REBUILD ONLIE(普通的REBUILD会检查索引的FLAG标志和这张表,如果冲突,也会失败)而SMON会进行一次清除工作,SMON做清除前首先要锁住日志表,如果这个索引相关的表还在变化,那么SMON可能无法锁住这张表,如果SMON锁表失败,就会放弃这次清理工作,等一段时间后再来清理。

解决办法:

ORACLE 10G:Oracle提供了一个存储过程来代替SMON做手工清除(DBMS_REPAIR.ONLINE_INDEX_CLEAN),只要不停的sysdba重复执行这个存储过程,就可能清除失败的索引。

DECLARE
  isClean BOOLEAN;
  BEGIN
    isClean := FALSE;
    WHILE isClean=FALSE
    LOOP
      isClean := dbms_repair.online_index_clean( dbms_repair.all_index_id, dbms_repair.lock_wait);
      dbms_lock.sleep(10);
    END LOOP;
  END;
  /Oracle 9i:

手工清除日志表,并修改索引的FLAGS。

手工解决这个问题分为两个步骤:

1、手工删除日志表: 首先找到这个索引的OBJECT_ID: Select object_id from dba_objects where owner=<owner> and object_name=<index name>;

OBJECT_ID后,就可以知道表的名字了(SYS_JOURNAL_<OBJECT_ID>),直接DROP这张表。不过如果这张表上的DML比较频繁,DROP操作可能不会一次成功,需要不停的重试。

、手工修改IND$: UPDATE IND$ SET FLAGS=FLAGS-512 WHERE OBJ#=<OBJECT_ID>;

这样相关表上没有了DML操作,很快SMON就会完成自动清理。