ORA-08104: this index object 67420 is being online built or rebuilt

 

今天在创建一个大表的索引的时候,online创建索引花费好长时间,没有反映;然后取消,结果删除索引的时候,报如下的错误:

 ORA-08104: this index object 67420 is being online built or rebuilt

 

     通过 ONLINE 参数创建索引(或者重建索引), 如果进程被突然终止,或者是手工 CTRL+C 取消该操作,在非常个别的时候,麻烦来了。重新创建索引,会告诉你该索引已经存在,drop index ,会告诉你该索引被锁,或者是 ORA-08104(this index object xxxxx is being online built or rebuilt) 错误。


该过程失败之前创建的一些临时对象由 SMON 负责清除,糟糕的是, SMON 可不是那么听话,马上出来清除,这个清除时间可能会很长,据说在 9i 上观察是 2 个小时才清除掉。

 

在Oracle10g之前,对于这种情况没有太好的办法,只有等SMON进程来进行清理了。网上有说上重启库可以解决,有说直接update系统表ind$的,对于不能停机的产品库来说,这些都是不可取的方案。重启不现实,修改系统表是DBA的大忌。

 

异常终止的情况下,可以发现ind$关于该索引的状态还是online rebuild的:

SQL> select obj#,flags from ind$ where obj#=67420;

      OBJ#      FLAGS
---------- ----------
     67420        514

Flags字段的说明可以在ind$的sql.bsq脚本中找到:

 514=0×202,表示该索引状态为index is being online rebuilt : 0×200 + analyzed : 0×02

/* 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 */
/* fake index(internal) : 0x1000 */
/* index on UROWID column(s) : 0x2000 */
/* index with large key : 0x4000 */
/* move partitioned rows in base table : 0x8000 */
/* index usage monitoring enabled : 0x10000 */

 

 

解决一:

 

在10g中用dbms_repair.online_index_clean来清除创建索引的失败的遗留


DECLARE
  RetVal BOOLEAN;
  OBJECT_ID BINARY_INTEGER;
  WAIT_FOR_LOCK BINARY_INTEGER;

BEGIN
  OBJECT_ID := 67420;
--  我的数据库中非法索引的id为67420.
  WAIT_FOR_LOCK := NULL;

  RetVal := SYS.DBMS_REPAIR.ONLINE_INDEX_CLEAN ();
  COMMIT;
END;

 

 

解决二:(这种方法没测试成功)

 

唤醒SMON:

WAKEUP command  :To wake up a process use

    ORADEBUG WAKEUP pid

For example to wake up SMON, first obtain the PID using

    SELECT pid FROM v$process
    WHERE addr =
    (
        SELECT paddr FROM v$bgprocess
        WHERE name = 'SMON'
    );


If the PID is 6 then send a wakeup call using

  sql > ORADEBUG WAKEUP 6

 

记录一下SMON的功能及其触发频率(9i):

 

Merging free extents or coalescing: every five minutes.

Cleaning up temporary segments: every two hours.

Updating SMON_SCN_TIME for used in time based flashback: every five minutes.

Cleaning up non existent objects in OBJ$: every 12 hours.

Cleaning up IND$ if online builder crashes: every hour.

Shrink undo segments:every 12 hours.

Transaction recovery only on startup.

Transaction rollback of dead transaction when posted by PMON, allowing the use of fast start parallel rollback if necessary.

 

解决方法三:

 

由于在做索引在线重建的时候,可能相关的表还在变化,Oracle需要记录这个索引的相关变化,因此Oracle会创建一张临时表来记录这些变化,等索引重建完成后再删除这张临时表,这张临时表的名字为SYS_JOURNAL_<INDEX的OBJECT_ID>。REBUILD ONLINE刚刚开始的时候就会去创建这张日志表,但是如果创建日志表的时候,发现这张表已经存在了,就可能会报ORA-8104,并无法继续做REBUILD ONLIE(普通的REBUILD会检查索引的FLAG标志和这张表,如果冲突,也会失败)。如果REBUILD ONLINE被中途杀掉了,那么这张表和IND$中的FLAGS不会被自动清除,必须由SMON来清除。而SMON每个小时会进行一次类似的清除工作,SMON做清除前首先要锁住日志表,如果这个索引相关的表还在变化,那么SMON可能无法锁住这张表,如果SMON锁表失败,就会放弃这次清理工作,等一个小时后再来清理。这样一来,在业务较为繁忙的生产系统上,可能SMON永远都没有机会清除这张日志表。

 

如果是9i的数据库就很麻烦了,如果系统smon进程无法清除,或者重启数据库也无法解决,那只有手工清除了日志表,并且修改索引的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操作可能不会一次成功,需要不停的重试。

2、手工修改IND$:

   UPDATE IND$ SET FLAGS=FLAGS-512 WHERE OBJ#=<OBJECT_ID>;

手工清理要十分小心,一旦出错会导致数据字典错误。

 

解决方法四:

 

还有一种稳妥的办法是把应用停了,然后重启数据库,这样相关表上没有了DML操作,很快SMON就会完成自动清理。

 

 

你可能感兴趣的:(ORA-08104: this index object 67420 is being online built or rebuilt)