暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

ORA-8102故障的分析与解决

白鳝的洞穴 2020-05-26
3411
这是一个2008年某银行的案例,当时某银行的审计库在导入一些新数据的时候出现了下面的错误:

上面这段报错的意思是出现了ora-8102错误,对象是obj# 49,相对文件号是8,块号是21882。看到报错信息我一看,心里就一慌,从对象的ID看,这是一个核心bootstrap对象,虽然是个索引,但是无法通过rebuild来解决。
于是我让他们马上做了一个10046 TRACE,这下子看到的信息更为明确了:

可以看出这是一个生成约束记录的算法,首先从con$表中找到NAME=_NEXT_CONSTRAINT的记录,然后+1,再修改CON$表,更改这个记录的值为新值。而取出的那个记录就应该是新产生约束条件的CON#

通过TRACE我们可以看到,UPDATECON#参数是686500,那么修改前这个值是686499,翻译成Oracle内部存储格式就是c3 45 41 64。这就是从TRACE中看到的出现oer 8102的那个key。根据TRACE信息可以看到rdba:0x0200557(8/21882)是一个叶节点块:

该块属于0x31对象,也就是OBJ#=49的对象(I_CON2),从块头来看,BLOCK并无异常。该块拥有193条记录(kdxconro 193),每条记录对应一条CON$表的记录:

 按常规_NEXT_CONSTRAINT应该在con$表刚刚建立的时候就已经产生,因此该记录应该位于1号文件,从这193条记录来看,只有最后一条记录0x004000aa00-11(1/4352011号记录)位于FILE 1,由于_NEXT_CONSTRAINTCON#是下一条CON$记录的CON#的值,因此该记录应该是该表中的CON#最大的记录,理应处于索引的最后一行。而从该行的值来看c3 45 42 0e,翻译成十进制值应该是:686514,这个值明显和686499不同。这就是导致ORA-8102的主要原因(这里已经十分明显,所以老白也就没有使用索引中的rowid再去验证了,正常的做法是通过rowid找到数据行,对比数据行中的数值与索引中是否一致)。

于是我让现场运维人员进行了一系列的实验,通过实验可以证明,任意创建一张不带任何约束条件的表能够正常完成,而一旦创建带有约束条件的表就会失败。

因此可以断定,这是由于CON$表和索引I_CON2索引之间键值不一致导致的故障。这种不一致一般来说是由于数据库出现逻辑故障导致,比如数据库宕机或者被shutdown abort,服务器出现内存故障等都可能造成类似的问题。这种问题较为少见。

由于CON$I_CON2都是小于56号的OBJ,属于核心BOOTSTRAP$对象,因此这些对象是不能随便重建的,因此无法通过REBUILD索引来解决ORA-8102故障。

这个数据库很大,虽然说数据都是可以从生产库再次生成的,所以客户不想重建数据库后重新构建整个数据,于是问我有没有可以不重建数据库就能解决问题的方法。我首先说,如果不创建约束关系,也是不会报错的,这个库还可以凑合用。但是用户觉得不创建约束关系比较困难,还是希望有其他的办法来解决。于是没有办法我只能祭出BBED来了。通过BBED把索引块中的数据与表块中的数据写成一致就没有问题了(取二者中的最大值)。首先通过:

select *+full(con$) */ con# from con$ where name='_NEXT_CONSTRAIN';

查看CON#的值,或者通过

alter system dumpdatafile 1 block 43520;

查看BLOCK DUMP中的第11号记录,看看CON#字段的值,我们的目的是将二者修改为较大的那个值。

于是我给他们提供了一个示例,让他们模仿这个例子远程处置。

制造故障

通过BBED,将CON$表中的_NEXT_CONSTRAINT的那一行的CON#6001改为6004.修改后重启数据库,然后操作:

SQL> conn scott/tiger

已连接。

SQL> create table tcon1( a integer);

 表已创建。

 SQL> create table tcon2( a integer notnull);

create table tcon2( a integer not null)

*

ERROR 位于第 1 :

ORA-00604: 递归 SQL 1 出现错误

ORA-08102: 未找到索引关键字,obj# 49dba 4277961 (2)

此时已经出现了类似的不一致。

分析故障

通过TRACE发现:

 

*** 2008-08-0816:56:58.984

*** SESSIONID:(12.7) 2008-08-08 16:56:58.984

oer 8102.2 - obj#49, rdba: 0x004146c9

kdk key 8102.2:

  ncol: 1, len: 4

  key: (4): 03 c2 3d 05

 

表中的值是C2 3D05   6004),通过TRACE查看索引的值:

BH (0x653EFC74)file#: 1 rdba: 0x004146c9 (1/83657) class 1 ba: 0x65273000

 

col 0; len 2;(2):  c2 3d

row#135[632] flag:-----, lock: 0, data:(6):  00 40 01 52 000c

col 0; len 3;(3):  c2 3d 02

 

索引中的值是c2 3d02(6001)

下面就需要将索引中的值设置为和表中一致,也就是02->05

从上述计算:632+44+24*itl槽位书(本案例是2=724

724开始应该是

00 00 00 40 01 52 00 0c 03 3d 02

因此735应该是02

 

bbed>print 735

rowdata[26]

-----------

ub1 rowdata[26]                             @735      0x02

解决故障

 

启动BBED

BBED>set file 1

BBED>set block 83657

BBED>modify x 0x05 735

BBED>sum apply

 

然后重启数据库:

SQL>create table tcon2( a integer not null);

 

表已创建。

 

成功解决了问题。



文章转载自白鳝的洞穴,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论