undo transaction slot被覆盖引起ORA(10)

上述dump中uba: 0x02000010.187e.18 ctl max scn: 0x0000.00ae9095正是来自于事务开始前undo header里TRN CTL部分所包含的uba: 0x02000010.187e.18 scn: 0x0000.00ae9095,而prv tx scn:0x0000.00ae909b 和prev brb:33554460 则分别等于事务开始前slot 0x1e 所对应的scn:00ae909b和dba:0x0200001c(转换成10进制就是33554460)。只有事务的首条undo记录才会保留上一版本的undo信息。将相关的undo记录串起来就可以完整的回放事务表所发生过的变更,下面较为直观的方式说明一下undo 记录间的指向关系,还是以proc1.sql里前三个事务为例,它们所使用的xid,uba如下:

XIDUSN,XIDSLOT,XIDSQN,UBAFIL,UBABLK,UBAREC,UBASQN  :  2,31,4563,8,20,27,6270

XIDUSN,XIDSLOT,XIDSQN,UBAFIL,UBABLK,UBAREC,UBASQN  :  2,2,4565,8,20,28,6270

XIDUSN,XIDSLOT,XIDSQN,UBAFIL,UBABLK,UBAREC,UBASQN  :  2,22,4564,8,20,29,6270

Undo record的记录是后修改的指向先修改的,所以依次dump block 8/20中 Rec #0x1d、Rec #0x1c、 Rec #0x1b的记录,仅将相关的内容摘录下来:

*-----------------------------

* Rec #0x1d  slt: 0x16  objn: 89731(0x00015e83)  objd: 89731  tblspc: 8(0x00000008)

*      Layer:  11 (Row)  opc: 1  rci 0x00

Undo type:  Regular undo    Begin trans    Last buffer split:  No

Temp Object:  No

Tablespace Undo:  No

rdba: 0x00000000Ext idx: 0

flg2: 0

*-----------------------------

uba: 0x02000014.187e.1c ctl max scn: 0x0000.00ae92ed prv tx scn: 0x0000.00ae92ee

txn start scn: scn: 0x0000.00ae9357 logon user: 0

prev brb: 33554451 prev bcl: 0

*-----------------------------

* Rec #0x1c  slt: 0x02  objn: 89731(0x00015e83)  objd: 89731  tblspc: 8(0x00000008)

*      Layer:  11 (Row)  opc: 1  rci 0x00

Undo type:  Regular undo    Begin trans    Last buffer split:  No

Temp Object:  No

Tablespace Undo:  No

rdba: 0x00000000Ext idx: 0

flg2: 0

*-----------------------------

uba: 0x02000014.187e.1b ctl max scn: 0x0000.00ae92ec prv tx scn: 0x0000.00ae92ed

txn start scn: scn: 0x0000.00ae9354 logon user: 0

prev brb: 33554451 prev bcl: 0

*-----------------------------

* Rec #0x1b  slt: 0x1f  objn: 89731(0x00015e83)  objd: 89731  tblspc: 8(0x00000008)

*      Layer:  11 (Row)  opc: 1  rci 0x00

Undo type:  Regular undo    Begin trans    Last buffer split:  No

Temp Object:  No

Tablespace Undo:  No

rdba: 0x00000000Ext idx: 0

flg2: 0

*-----------------------------

uba: 0x02000014.187e.18 ctl max scn: 0x0000.00ae92eb prv tx scn: 0x0000.00ae92ec

txn start scn: scn: 0x0000.00000000 logon user: 0

prev brb: 33554451 prev bcl: 0

通过这三个undo Record能够映射得到前一时刻的undo事务表,假设T3>T2>T1>T0,以下图示能够直观的展现这一映射关系:
 

上面的图能够帮助我们理解oracle是如何实现事务表的回滚,只要undo block不被覆盖,就能回滚得到足够旧的事务表。

具备了上述知识点后,我们分析一下session 2是如何成功遍历scott.tabnow1表的:

(1)    Session 2的select语句执行时的snapshot scn近似等于ae931d

(2)    访问rdba:4/1779 时发现Itl列表里slot 0x02还处于活动状态,且没有commit scn,于是就到xid所指向的undo 事务表进一步查询事务是否提交,slot 0x1e的state=9表示事务已经提交,但提交时的wrap#值为0x11dc远大于0x11d2,且undo 事务表头的control scn:ae96dc远大于snapshot scn: ae931d

(3)    Oracle判断事务表槽已slot 0x1e已经被覆盖,需要回滚事务表,回滚的起点是8/14 Rec #0x21,这个Record是proc1.sql中第337个transaction所使用的undo record,因为正是这个transaction完成了对undo slot 0x1e的最后一次覆盖

(4)    接下来将如上图所示,oracle一步一步的对事务表进行回滚,每重构出一个事务表的版本后,将事务表头部的control scn和snapshot scn进行比较,如果snapshot scn<control scn则继续进行回滚,直到snapshot scn>=control scn而且wrap#的值等于0x11d2,事务表才回滚完毕,从undo record :8/16  Rec #0x19里读出修改前的值:

select utl_raw.cast_to_varchar2(replace('58 53 24 4e 55 4c 4c 4c 4c',' ')) from dual;

UTL_RAW.CAST_TO_VARCHAR2(REPLACE('5853244E554C4C4C4C',''))

--------------------------------------------------------------------------------

XS$NULLLL

Session 2实现一致性读的两个统计信息:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/31adee041cbfddebdb0c76723168ed2c.html