一、问题表象:
最近遇到一个奇怪的问题,oracle数据库大量undo段迟迟不expired, 最终导致undo不够用,引发一系列undo相关报错,关于隐患参数_undo_autotune是false。v$undostat 始终只有一行,数据一直累加,而正常环境应该是5分钟有一条新纪录。多次尝试重建undo没作用,Undo unexpire还是持续上涨, 修改undo_retention为10800(3小时), _highthreshold_undoretention也改为10800,仍然不起作用。
当出现断电或硬件故障数据库崩溃或者bug等,通常会发生此问题。启动时,数据库先进行正常的前滚(重做),然后再进行回滚(撤消),这是在回滚时生成错误的地方。根据官方文档:ORA-600 [4193] “seq# mismatch while adding undo record” (Doc ID 39282.1)的描述,在重做记录和回滚记录之间检测到不匹配。
常规情况,可以通过重建undo来解决
二、问题分析
从 Oracle 9i 开始,oracle引入了一种管理前镜像的新方式. 之前的版本这是通过 RollBack Segment 进行的,或称为 manual undo(手动 undo)。 Oracle引入回滚段的目的: 1、事务回滚 2、数据库恢复 3、提供读一致性 4、数据库闪回查询(9i引入) 5、利用闪回特性可以恢复 具体的报错,smon具体的报错信息如下:
这里的XID,上面的第七行,表示当前undo block所记录的事务xid,对应V$TRANSACTION.XID信息。
xid: 0x00a8.01d.03d46b1f 0x00a8 --回滚段编号,转换后为168,说明该事务使用的回滚段是第168号回滚段 01d --事务槽编号(slot),转换后为29,说明对应undo segment header中的transaction table记录中的index是29 03d46b1f --序号(同一个事务可能具有多个SCN,用于区分一个事务中的多个操作) 看下trace里的ktuxc的信息,ktuxc的结构在undo segment header中
任何时候,一个事务只能使用一个undo block。当然,在Tx 事务表头(ktuxc)中,没有必要存放整个完整的uba地址,存放undo block的dba地址就足够了。事务用这个来指向最近被使用的undo block、块头包含了一个指针,指向了该事务所创建的的最新undo record记录。之前的记录都保存在同一个block或者在另外一个undo block中。undo chain的最末端是是没有dba地址,rci就是undo chain。 事务回滚的完整流程: 1、首先通过TX table header(ktuxc)找到的uba地址 2、通过Tx table中的uba地址,定位到最新使用的undo block地址 3、根据最新的undo block定位到最新的undo record Doing block recovery for file 8 block 2201054,这里数据尝试去恢复这个块,这个块是undo数据文件的块,也就是,uba:0x022195de.eeab.01对应的回滚段的块。
准备将这个块dump出来,发现提示无效的rowid。将这个块从asm到本地,发现无法拷贝。后来了解到,8号数据文件也就是undo数据文件,已经经过多次重建,已经找不到之前的数据块。
三、解决方法 通过上面的分析,发现通过Tx table中的uba地址,定位到最新使用的undo block地址,这个块根本不存在,多次尝试重建undo没作用。 解决方法: 1、隐含参数*._corrupted_rollback_segments、._offline_rollback_segments。 2、10513 event来禁止smon 进行事务恢复(不一定起作用)。 3、通过bbed修改system回滚段的块,清除free block pool,让oracle认为没有可用的undo block了。 system检查没有坏块。
smon的trace不再报错,恢复正常。
|