关于undo机制的总结[收集中]

摘要:

      事务表是在undo段的段头块上的,事务表里每个数据行记录事务的事务编号XID及该事务对应的用于保存事务所要修改的表的数据行的原先值的undo块(该undo块当然是位于该事务表所在的undo段里)的地址等,事务所要修改的表里的数据块的块头(层)上有事务槽,用于存放修改本数据块的事务的的事务编号XID等信息,当然事务槽上的事务若已经提交了,那么这个事务槽就可以被其他事务使用了(即覆盖)。


一、undo记录的rowid信息和各DML操作产生的undo记录大小比较


1、update : 在Undo中记录被更新列的前镜像和被更新行ROWID;
2、delete : 在Undo中记录被删除行所有列的前镜像和其ROWID;
3、insert : 在Undo中记录插入行的ROWID。

所以,按对应产生的undo记录所占空间的大小从小到大排列依次是insert(只记录rowid),update,delete。

这里,有一点要说明的是在UNDO中记录的例如Insert操作对应的插入行的ROWID并非是直接记录的,而是要拼凑出来的。

以下,以Insert操作为例子看看其对应产生的undo记录如何拼凑出rowid信息:

SQL> create table test (a number,b varchar2(10));
 
Table created.
 
SQL> insert into test values(1,'a');
 
1 row created.
 
SQL> insert into test values(2,'b');
 
1 row created.
 

下面Rec0x8undo记录就是对应于insertinto test values(2,'b');语句产生的

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

Rec #0x8 slt: 0x18objn: 6469(0x00001945)objd: 6469tblspc: 0(0x00000000)*

Layer:11 (Row) opc:1 rci 0x07

Undotype: Regular undo Last buffer split: No

TempObject: No

TablespaceUndo: No

rdba:0x00000000

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

KDOundo record:

KTBRedo

op:0x02 ver: 0x01

op: Cuba: 0x0200002e.08ab.07

KDO Opcode: DRP row dependencies Disabled

xtype:XA bdba: 0x00403bdehdba: 0x00403bdd

itli: 1ispac: 0 maxfr:4863

tabn: 0slot: 2(0x2)

没发现ROWID的影子,看来是要通过一些字段拼凑起来了:
“objd: 6469”
对应ROWID中的DATA_OBJECT_ID#
“bdba: 0x00403bde”
对应ROWID中的rfile#block#
“slot: 2(0×2)”
对应ROWID中的ROW#

 

二、段头块里的事务表的解读

TRC内容,部分内容略掉

 index  state cflags  wrap#   uel         scn            dba            parent-xid    nub    stmt_num    cmt

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

  0x00    9    0x00 0x02df  0x000b  0x0000.003f4409  0x00c00c65 0x0000.000.00000000  0x00000001   0x00000000 1354068343

  0x01    9    0x00 0x02e2  0x0000  0x0000.003f43ff  0x00c00c65 0x0000.000.00000000  0x00000001   0x00000000 1354068343

  0x02    9    0x00 0x02e1  0xffff  0x0000.003f4de1  0x00c00c61 0x0000.000.00000000  0x00000001   0x00000000 1354074347

  0x03   10    0x80 0x02e2  0x0002  0x0000.003f4e6f  0x00c00c61 0x0000.000.00000000  0x00000001   0x00000000 0

  0x04    9    0x00 0x02e2  0x000c  0x0000.003f4592  0x00c00c65 0x0000.000.00000000  0x00000001   0x00000000 1354069244

-- 索引(index),即事务表上槽号为0x03的行,state为10,cflags为0x80,表示此行是活动(active)事务。

state为9,表示事务是非活动的(可能为expired或unexpired吧)

-- wrap#为0x02e2,等于v$transaction里的XIDSQL值,也就是回滚槽被重用了738次。

-- uel为0x0002,表示事务当前区,和v$rollstat查到的CUREXT(当前区编号)一致。

-- scn为0x0000.003f4e6f,转换为十进制是4148847,和v$transaction的START_SCNB()值相符。

-- dba为0x00c00c61,事务对应产生的undo块所在的数据文件编号、块编号

--cmt为0,表示该事务未提交

 

三、undo块里信息的解读

 

跟踪文件XXXX.TRC内容,部分内容略
UNDO BLK:
xid: 0x0009.003.000002e2  seq:0xd1  cnt:0x24  irb:0x24  icl: 0x0   flg: 0x0000
 
 Rec Offset      Rec Offset      Rec Offset      Rec Offset      Rec Offset
---------------------------------------------------------------------------
0x01 0x1f90     0x02 0x1f28     0x03 0x1ee4     0x04 0x1e80     0x05 0x1e00
0x06 0x1c58     0x07 0x1c04     0x08 0x1b44     0x09 0x1b00     0x0a 0x1a9c
0x0b 0x19d8     0x0c 0x197c     0x0d 0x121c     0x0e 0x11d8     0x0f 0x1174
0x10 0x110c     0x11 0x10a8     0x12 0x0f20     0x13 0x0edc     0x14 0x0e78
0x15 0x0e28     0x16 0x0d6c     0x17 0x0cbc     0x18 0x0c10     0x19 0x0b64
0x1a 0x0ab4     0x1b 0x0a08     0x1c 0x093c     0x1d 0x0890     0x1e 0x07e4
0x1f 0x0738     0x20 0x0688     0x21 0x05e4     0x22 0x0558     0x23 0x0500
0x24 0x04a0
-- seq: 0xd1指的就是v$transaction中的UBASQN字段
-- cnt: 0x24表示该undo块中有0x24条undo块的undo记录(行)
-- irb : 0x24,表示回滚链尾端undo记录号为0x24(即REC为0x24的undo记录(行),也即第0x24号undo记录(行))的undo记录,也就是v$transaction中的UBAREC字段
注释:回滚链(undo chain)就是指一个事务里的先后产生的多个DML操作对应的undo记录由后指向前组成的(以undo记录里的rci为指针)
 
根据irb : 0x24,查找Rec #0x24
*-----------------------------
*Rec#0x24  slt: 0x03  objn: 24633(0x00006039)  objd: 24633  tblspc: 6(0x00000006)
*       Layer:  11 (Row)   opc: 1   rci 0x23
Undo type:  Regular undo   Last buffer split:  No
Temp Object:  No
Tablespace Undo:  No
rdba: 0x00000000
*-----------------------------
KDO undo record:
KTB Redo
op: 0x02  ver: 0x01
compat bit: 4 (post-11) padding: 1
op: C  uba: 0x00c00c61.00d1.22
KDO Op code: URP row dependencies Disabled
  xtype: XA flags: 0x00000000  bdba:0x020000de  hdba:0x020000da
itli: 2  ispac: 0  maxfr: 4858
tabn: 0 slot: 1(0x1) flag: 0x2c lock: 0 ckix: 0
ncol:2 nnew:1 size: 4
col  1: [ 6]  4f 52 41 43 4c 45
-- objn: 24633(0x00006039)指的是该undo记录所对应的那个被修改的对象(如表)的逻辑对象号object_id
objd: 24633该undo记录所对应的那个被修改的对象(如表)的对象号data_object_id
 tblspc: 6(0x00000006) 指的是该undo记录所对应的那个被修改的对象(如表)所在的表空间号
-- hdba:0x020000da指的是该被修改的表所在的段的段头块的地址
bdba:0x020000de指的是该表里具体的那个被修改的数据行所在段里的数据块的地址
-- ncol:2指的是该被修改的表有几列
   nnew:1指的是该被修改的表的一行实际被修改了几列
 
-- rci 0x23,且rdba:0x00000000,表示回滚记录都在此块儿上面(应该说是上回滚记录在此undo块儿上面);如果rdba非0,那就代表回滚链中前一个块所在的位置(或者说如果rdba非0,那rdba值就代表回滚链中前一个undo记录所在的undo块的地址位置
我们可以根据它的值再dump相关block查看。
-- col  1: [ 6]  4f 52 41 43 4c 45,就是我做最后一次update的前镜像

 

 

 附加:

若一个事务产生了五万条undo记录,一个undo块的空间一般是放不下五万条undo记录的,所以这个五万条记录会分布在不同的undo块(这几个undo块不是说要连续放在一起的,随机的)上,那么这个事务对应的事务槽上的uba字段的地址是指向哪个undo记录的呢?

一个DML操作对应会产生一个undo记录,一个包含多个DML操作的事务,其对应的事务槽上的uba字段的地址都是指向该事务里最后一个DML操作所对应的undo记录的地址的(undo块中irb指的就是这个uba地址的第三部分,即REC部分)。无论这个事务对应产生的undo记录是放在一个undo块上,还是多个undo块上,都是这样的。

一个事务对应产生的多个undo记录是如何组织在一起的呢?

就是通过undo chain。

回滚链(undo chain)就是指一个事务里的先后产生的多个DML操作对应的undo记录由后指向前组成的(以undo记录里的rci为指针将这几个记录连接在一起的)。
  如何判断在undo chain上的上一个undo记录是否跟本undo记录位于同一个undo块上?

就是通过本undo记录里的rdba来判断的。

rdba:0x00000000,表示回滚记录都在此块儿上面(应该说是上回滚记录在此undo块儿上面);如果rdba非0,那就代表回滚链中前一个块所在的位置(或者说如果rdba非0,那rdba值就代表回滚链中前一个undo记录所在的undo块的地址位置

 四、undo的作用之一事务回滚机制(以下基于推测未试验过)

首先,要说明的是,在一个会话窗口上输入事务回滚命令rollback后所产生的回滚操作只针对该会话下的未提交的事务,对(同一时间)其他会话下的未提交的事务不影响。

undo的另一个作用,即一致性读,也是和会话有关的。例如,表T上一行的name字段值原来为A。现在在会话1下,将之改为B(未提交),接着,还在会话1下,select该行的name字段的值,结果为B。而接下来,在会话2下,select该行的name字段的值,结果为A。所以,undo机制与会话有关的。

会话(内存)上应该记录了会话期间修改了哪些表,(以及这些表最近一次提交时间SCN,)还有在会话里输入rollback命令前的所有(未提交)事务的XID(即事务槽上的XID字段)信息。

这样,当会话里输入rollback命令时,服务器进程就会扫描各个修改过的表的各个数据块上的所有事务槽(当然也包括其他会话里的事务所占的事务槽)的flag是否为提交,若是为未提交(因为块延迟清除机制,这里的未提交不表示真的未提交,还得找事务表上的提交标记),还得根据事务槽上的XID字段找到段头块上的事务表里的对应行,看该行的cmt是否为提交,为提交,就是真的提交,为未提交,就是真的未提交。如果这里为未提交,还要查看该未提交事务所在的事务槽的XID字段是否属于会话里记录过的事务XID,若不是,就跳过该事务(因为该事务属于其他会话的),若是,则就可以根据该未提交事务所在的事务槽的uba字段找到其前镜像,通过该前镜像信息,将当前数据块还原为没开始执行该未提交事务前的状态,这个过程和构造CR块的过程是一样的,只不过构造CR块前先复制一个当前块的副本,在这个副本进行还原。

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值