[ORA-08104] this index object XXX is being online built or rebuilt

来源:互联网 发布:怎样装修淘宝店铺首页 编辑:程序博客网 时间:2024/05/19 13:42

背景:

在进行联机重建索引的过程中出现错误,如用户终止,网络中断等,那么当我们再次重建索引时,有可能产生ORA-08104错误。

alter index index_name rebuild online;

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

删除(包括force选项)时均无法删除。

原因:

create /rebuild index online时会修改数据库字典表obj$,并在该索引用户下创建表sys_journal_obj#(具体的对象号)和在ind$、ind_online$表里(ind_online$字典基表记录了

索引在线创建/重建的历史)标记256或512,(11g里rebuild online是514??)。
如果服务器进程在语句执行过程中意外终止的话,可能会导致相关在ind$标记位信息及在线日志中间表不能及时处理及清除(清除动作一般有smon进程处理,如果重建过程异常

中断,smon会清理重建痕迹,但是如果系统非常繁忙导致smon无法清除,或dml操作频繁,导致smon无法获取相关表上的锁,从而造成无法清理痕迹,当再次重建索引或对表进行dml

操作会报本篇提示错误),这将导致对该索引的后续操作因ora-08104错误而无法继续,如果是分区表,索引是global,在添加分区也无法继续。

对此进行验证

select i.obj#, i.flags, u.name, o.name, o.type#    from sys.obj$ o, sys.user$ u, sys.ind_online$ i   where (bitand(i.flags, 256) = 256 or bitand(i.flags, 512) = 512)     and (not ((i.type# = 9) and bitand(i.flags, 8) = 8))     and o.obj# = i.obj#     and o.owner# = u.user#;  

可以发现ind$关于该索引的状态还是online rebuild的:

SQL> select obj#,flags from ind$ where obj#=67420;      OBJ#      FLAGS---------- ----------     67420        514 Flags字段的说明可以在ind$的sql.bsq脚本中找到: /* 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 */514=0×202,表示该索引状态为index is being online rebuilt : 0×200 + analyzed : 0×02
在SMON完成清理动作后,再次查询索引状态已经恢复正常:

SQL> select obj#,flags from ind$ where obj#=67420;      OBJ#      FLAGS---------- ----------     67420          2
清理完后,可以在alert.log中看到如下记录:
User:,time:20071209 03:12:09,program:oracle@db1 (SMON),IP:,object:SYS_JOURNAL_67420,DDL: drop table "TAOBAO"."SYS_JOURNAL_67420"


解决办法:

建议SMON进程自动清理

解决方法一、使用存储过程dbms_repair.online_index_clean来清理

11G中

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(2);  end loop;  exception  when others then  RAISE;  end;  /   
注意事项:在执行过程中,需要在索引所在表上获取锁,因此应尽可能的保证索引表不被其他事务锁定,以尽快清理临时数据,如果长时间不能清除数据,查看后台日志,我们会发现
Mon Dec 07 19:33:51 2015online index (re)build cleanup: objn=114615 maxretry=2000 forever=0
如果一直不成功,一个可选方法是将此索引对应表的TM锁的进程KILL;

使用如下语句查询:

select object_name,s.sid,s.serial#,p.spid  from v$locked_object l , dba_objects o , v$session s , v$process p  where l.object_id=o.object_id and l.session_id=s.sid and s.paddr=p.addr and object_name='XXX';
解决方法二:使用ORADEBUG唤醒SMON进程进行清理
SYS用户登陆:select status,instance_name from v$instance;  select pid,spid from v$process p,v$bgprocess b where b.paddr=p.addr and name='SMON';         PID SPID  ---------- ------------------------          22 1741  oradebug wakeup 22    select status,instance_name from v$instance; 
此步骤可以多次尝试。关于为什么SMON进程未清理掉,可能是未到达SMON进程清理的阀值,或者与当时数据库负载等多种因素有关。
网上解释有:
SMON负责在启动后(startup)的每小时执行一次对IND$基表中因在线创建/重建索引失败所留下记录的清理,这种清理工作由kdicclean函数驱动(kdicclean is run by smon every 1 hour,called from SMON to find if there is any online builder death and cleanup our ind$ and obj$ and drop the journal table, stop journaling)。 这种清理工作典型的调用堆栈stack call如下:
ksbrdp -> ktmSmonMain ktmmon -> kdicclean -> kdic_cleanup -> ktssdrp_segment
注意因为SMON进程的清理工作每小时才执行一次,而且在工作负载很高的情况下可能实际很久都不会得到清理,
OBJ$基表是一张低级数据字典表,该表几乎对库中的每个对象(表、索引、包、视图等)都包含有一行记录。很多情况下,这些条目所代表的对象是不存在的对象(non-existent),引起这种现象的一种可能的原因是对象本身已经被从数据库中删除了,但是对象条目仍被保留下来以满足消极依赖机制(negative dependency)。因为这些条目的存在会导致OBJ$表不断膨胀,这时就需要由SMON进程来删除这些不再需要的行。SMON会在实例启动(after startup of DB is started cleanup function again)时以及启动后的每12个小时执行一次清理任务(the cleanup is scheduled to run after startup and then every 12 hours)。

如果方法2唤醒SMON进程进行清理也不成功,建议是安排停机时间,重启数据库实例了。
如果实在不方便重启数据库实例,对此索引又可以暂时不执行DDL操作,那么可以暂时忽略(此时原索引状态是VALID,不影响使用),等待停机窗口对数据库实例进行重启。
如果实在不方便重启数据库实例又需要重建索引(如索引遇到ORA-08102错误),那么还有一招是修改数据库字典基表,这个方法就不介绍了,生产环境是不会用的;并且底层基表多数存在互相关联,容易出错,慎用!!!

手工修改数据字典,清除中间表(未进行测试) 
sql>update ind$ set flags=flags-512 where obj#=<object id>; /* 首先要确认flags>512如果不是,说明这个标志是正常的*/
sql>drop table <owner>.sys_journal_<object_id>; /*这个步骤可能会报资源忙,因为有大量的日志正在插入,可以反复重试一下 */
注意顺序操作顺序,不到万不得已,不要修改数据字典

参考:

http://blog.csdn.net/yidian815/article/details/16844861

http://blog.csdn.net/haibusuanyun/article/details/50236057

阅读全文
0 0
原创粉丝点击