love wife love life —Roger的Oracle/MySQL/PostgreSQL数据恢复博客

Phone:18180207355 提供专业Oracle/MySQL/PostgreSQL数据恢复、性能优化、迁移升级、紧急救援等服务

Oracle 里面如何实现只回滚某个事务的一部分内容

昨天凌晨被电话吵醒,某客户的一套11gR2 RAC出现异常,正常启动之后很快就crash掉,并伴随相关ora-00600错误。
通过alert log发现如下信息:

从上面的信息我们可以看出,smon进程在对object进行事务rollback时,事务(例如114,16)存在异常,导致smon无法进行正常的工作,进而导致smon进程dead,最后pmon 进程将实例终止掉。
这里我们以最开始的一个事务(114,16) 进行举例分析。

通过查看trace 文件我们发现,该事务信息存在异常,如下:

从trace的内容我们可以看出smon 进程rollback时,发现该事务回滚时访问的uba的地址跟需要信息不匹配或者相关信息不正确,即该undo block中的信息可能异常异常。 XID和UBA的结构解释如下:

xid:
0x0072.010.0006fa20

0072     :回滚段编号,转换后为114,说明该事务使用的回滚段是第114号回滚段

010      :事务槽编号(slot),转换后为16,说明对应undo segment header中的transaction table记录中的index是16

0006fa20 :序号(同一个事务可能具有多个SCN,用于区分一个事务中的多个操作)

uba: 0x3288715c.1195.20

3288715c: undo block地址,为16进制,转换为10进制为847802716,即(202/553308)

1195 :   sequence number

20 :     undo record编号

根据前面的信息判断,Oracle 利用undo block对事务进行rollback时,发现undo block中对应的记录不对,因此抛出ora-00600 [ktubko_1] 错误。我们知道Oracle 中的事务,必须保持其完整性,即一个事务要么成功,要么失败,不能只完成其中的部分操作(如果一个事务涉及到多个操作的 话)。那么能否实现只对事务中的部分操作进行rollback呢? 如果这个case中,能实现部分操作的rollback,那么就可以顺利打开数据库。当然这里我的处理方式是通过100513 event来屏蔽Smon进程的rollback操作,open之后再去维护相关的Index。

我们知道smon 在对一个事务进行回滚时,如果该事务涉及到多个操作,那么如何去保证顺序的回滚呢 ?其实是根据undo chain来的。
当rollback到rci为0时就结束该事务的rollback。 这里我举个测试例子,针对分区表带索引的操作。 当分区表的数据操作时,
那么必然会维护Index,因此同一个操作,在undo record中应该有2个record记录,下面我们来测试下,能否是否只回滚该事务
的部分操作,如下是我的测试例子,生产库不要随便玩~~~~

针对分区表的delete操作,如上述的例子,很简单,由于客户这里遇到的情况是insert,下面我来看下insert的情况。

既然我们知道Oracle是根据rci进行回滚的,那么针对该事务,涉及到2个操作,第1个是Rec 0x34是针对index的操作。
第2个操作是Rec 0x33,这是针对该index所在的分区表的操作。 我们知道这是一个完整的事务,那么能否实现只回滚第1个操作,因为后面的
record 可能存在问题或异常,导致smon无法正常完成。 如果能实现只回滚部分事务,那么就可以顺利打开数据库。

实际上要实现这一点,很简单,我们仅仅需要修改rci值即可实现,当然,这样操作,实际上就牺牲了事务的完整性.

 

对我们来讲关键的地方是:0a160f33 正确的顺序是:330f160a 其中,33表示rci值,0f是slot,16是opcode,0a表示Layer 编号值. 下面我们来试试,能否实现我们的需求:

 

我们可以看到,顺利打开数据库。 你会发现我们前面最开始insert了一条记录,通过全表扫描能够查询到,如果
走Index就不行。因为Index 中的记录被smon 进程rollback掉了。注意,如果在最开始的操作中,如果没有flush buffer_cache,
那么可能记录没有写到table中去,仍然会查询不到。
如果然而这种情况下,如果你去对表进行校验,会出现错误类似如下。我们正确的做法是,
将Index 进行重建,建议进行drop,然后create。 当然,这里如下你去看trace,会看到类似如下的内容:

很明显,牺牲事务的完整性之后,这个table和Index的信息不一致了。当然,我们要做的仅仅是重构Index即可。

如果是有针对table的操作,那么可能会丢失数据,需要权衡。

 

One Response to “Oracle 里面如何实现只回滚某个事务的一部分内容”

  1. wisdomone1 Says:

    牛圣ROGER,顶起

Leave a Reply

You must be logged in to post a comment.