关于undo机制的总结[收集中]
2013-09-03 17:29
204 查看
摘要:
事务表是在undo段的段头块上的,[b]事务表里每个数据行记录事务的事务编号XID及该事务对应的用于保存[b]该[b]事务所要修改的表的数据行的原先值的undo块(该[b][b]undo块[/b][/b]当然是位于该事务表所在的undo段里)的地址等,[b][b][b]事务所要修改的表里的数据块的块头(层)上有事务槽,用于存放要修改本数据块的事务的的事务编号XID等信息,当然事务槽上的事务若已经提交了,那么这个事务槽就可以被其他事务使用了(即覆盖)。[/b][/b][/b][/b][/b][/b]
[b][b][b][/b][/b]
[/b]
一、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>createtabletest(anumber,bvarchar2(10));
Tablecreated.
SQL>insertintotestvalues(1,'a');
1rowcreated.
SQL>insertintotestvalues(2,'b');
1rowcreated.
下面Rec为0x8的undo记录就是对应于insertinto
testvalues(2,'b');语句产生的
*-----------------------------*
Rec#0x8slt:0x18objn:6469(0x00001945)objd:6469tblspc:0(0x00000000)*
Layer:11(Row)opc:1rci0x07
Undotype:RegularundoLastbuffersplit:No
TempObject:No
TablespaceUndo:No
rdba:0x00000000
*-----------------------------
KDOundorecord:
KTBRedo
op:0x02ver:0x01
op:Cuba:0x0200002e.08ab.07
KDOOpcode:DRProwdependenciesDisabled
xtype:XAbdba:0x00403bdehdba:0x00403bdd
itli:1ispac:0maxfr:4863
tabn:0slot:2(0x2)
没发现ROWID的影子,看来是要通过一些字段拼凑起来了:
[b]“objd:6469”对应ROWID中的DATA_OBJECT_ID#
“bdba:0x00403bde”对应ROWID中的rfile#,block#
“slot:2(0×2)”对应ROWID中的ROW#[/b]
二、段头块里的事务表的解读
TRC内容,部分内容略掉
indexstatecflagswrap#uelscndbaparent-xidnubstmt_numcmt
------------------------------------------------------------------------------------------------
0x0090x000x02df0x000b0x0000.003f44090x00c00c650x0000.000.000000000x000000010x000000001354068343
0x0190x000x02e20x00000x0000.003f43ff0x00c00c650x0000.000.000000000x000000010x000000001354068343
0x0290x000x02e10xffff0x0000.003f4de10x00c00c610x0000.000.000000000x000000010x000000001354074347
0x03100x800x02e20x00020x0000.003f4e6f0x00c00c610x0000.000.000000000x000000010x000000000
0x0490x000x02e20x000c0x0000.003f45920x00c00c650x0000.000.000000000x000000010x000000001354069244
--索引(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块里信息的解读
附加:
若一个事务产生了五万条undo记录,一个undo块的空间一般是放不下五万条undo记录的,所以这个五万条记录会分布在不同的undo块(这几个undo块不是说要连续放在一起的,随机的)上,那么这个事务对应的事务槽上的uba字段的地址是指向哪个undo记录的呢?
一个DML操作对应会产生一个undo记录,一个包含多个DML操作的事务,其对应的事务槽上的uba字段的地址都是指向该事务里最后一个DML操作所对应的undo记录的地址的(undo块中irb指的就是这个uba地址的第三部分,即REC部分)。无论这个事务对应产生的undo记录是放在一个undo块上,还是多个undo块上,都是这样的。
一个事务对应产生的多个undo记录是如何组织在一起的呢?
就是通过undochain。
如何判断在undochain上的上一个undo记录是否跟本undo记录位于同一个undo块上?
就是通过本undo记录里的rdba来判断的。
四、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块前先复制一个当前块的副本,在这个副本进行还原。
事务表是在undo段的段头块上的,[b]事务表里每个数据行记录事务的事务编号XID及该事务对应的用于保存[b]该[b]事务所要修改的表的数据行的原先值的undo块(该[b][b]undo块[/b][/b]当然是位于该事务表所在的undo段里)的地址等,[b][b][b]事务所要修改的表里的数据块的块头(层)上有事务槽,用于存放要修改本数据块的事务的的事务编号XID等信息,当然事务槽上的事务若已经提交了,那么这个事务槽就可以被其他事务使用了(即覆盖)。[/b][/b][/b][/b][/b][/b]
[b][b][b][/b][/b]
[/b]
一、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>createtabletest(anumber,bvarchar2(10));
Tablecreated.
SQL>insertintotestvalues(1,'a');
1rowcreated.
SQL>insertintotestvalues(2,'b');
1rowcreated.
下面Rec为0x8的undo记录就是对应于insertinto
testvalues(2,'b');语句产生的
*-----------------------------*
Rec#0x8slt:0x18objn:6469(0x00001945)objd:6469tblspc:0(0x00000000)*
Layer:11(Row)opc:1rci0x07
Undotype:RegularundoLastbuffersplit:No
TempObject:No
TablespaceUndo:No
rdba:0x00000000
*-----------------------------
KDOundorecord:
KTBRedo
op:0x02ver:0x01
op:Cuba:0x0200002e.08ab.07
KDOOpcode:DRProwdependenciesDisabled
xtype:XAbdba:0x00403bdehdba:0x00403bdd
itli:1ispac:0maxfr:4863
tabn:0slot:2(0x2)
没发现ROWID的影子,看来是要通过一些字段拼凑起来了:
[b]“objd:6469”对应ROWID中的DATA_OBJECT_ID#
“bdba:0x00403bde”对应ROWID中的rfile#,block#
“slot:2(0×2)”对应ROWID中的ROW#[/b]
二、段头块里的事务表的解读
TRC内容,部分内容略掉
indexstatecflagswrap#uelscndbaparent-xidnubstmt_numcmt
------------------------------------------------------------------------------------------------
0x0090x000x02df0x000b0x0000.003f44090x00c00c650x0000.000.000000000x000000010x000000001354068343
0x0190x000x02e20x00000x0000.003f43ff0x00c00c650x0000.000.000000000x000000010x000000001354068343
0x0290x000x02e10xffff0x0000.003f4de10x00c00c610x0000.000.000000000x000000010x000000001354074347
0x03100x800x02e20x00020x0000.003f4e6f0x00c00c610x0000.000.000000000x000000010x000000000
0x0490x000x02e20x000c0x0000.003f45920x00c00c650x0000.000.000000000x000000010x000000001354069244
--索引(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内容,部分内容略
UNDOBLK:
xid:0x0009.003.000002e2seq:0xd1cnt:0x24irb:0x24icl:0x0flg:0x0000
RecOffsetRecOffsetRecOffsetRecOffsetRecOffset
---------------------------------------------------------------------------
0x010x1f900x020x1f280x030x1ee40x040x1e800x050x1e00
0x060x1c580x070x1c040x080x1b440x090x1b000x0a0x1a9c
0x0b0x19d80x0c0x197c0x0d0x121c0x0e0x11d80x0f0x1174
0x100x110c0x110x10a80x120x0f200x130x0edc0x140x0e78
0x150x0e280x160x0d6c0x170x0cbc0x180x0c100x190x0b64
0x1a0x0ab40x1b0x0a080x1c0x093c0x1d0x08900x1e0x07e4
0x1f0x07380x200x06880x210x05e40x220x05580x230x0500
0x240x04a0
--seq:0xd1指的就是v$transaction中的UBASQN字段
--cnt:0x24表示该undo块中有0x24条undo块的undo记录(行)
--irb:0x24,表示回滚链尾端undo记录号为0x24(即REC为0x24的undo记录(行),也即第0x24号undo记录(行))的undo记录,也就是v$transaction中的UBAREC字段
注释:回滚链(undochain)就是指一个事务里的先后产生的多个DML操作对应的undo记录由后指向前组成的(以undo记录里的rci为指针)
根据irb:0x24,查找Rec#0x24
*-----------------------------
*Rec#0x24slt:0x03objn:24633(0x00006039)objd:24633tblspc:6(0x00000006)
*Layer:11(Row)opc:1rci0x23
Undotype:RegularundoLastbuffersplit:No
TempObject:No
TablespaceUndo:No
rdba:0x00000000
*-----------------------------
KDOundorecord:
KTBRedo
op:0x02ver:0x01
compatbit:4(post-11)padding:1
op:Cuba:0x00c00c61.00d1.22
KDOOpcode:URProwdependenciesDisabled
xtype:XAflags:0x00000000bdba:0x020000dehdba:0x020000da
itli:2ispac:0maxfr:4858
tabn:0slot:1(0x1)flag:0x2clock:0ckix:0
ncol:2nnew:1size:4
col1:[6]4f5241434c45
--objn:24633(0x00006039)指的是该undo记录所对应的那个被修改的对象(如表)的逻辑对象号object_id
objd:24633该undo记录所对应的那个被修改的对象(如表)的对象号data_object_id
tblspc:6(0x00000006)指的是该undo记录所对应的那个被修改的对象(如表)所在的表空间号
--hdba:0x020000da指的是该被修改的表所在的段的段头块的地址
bdba:0x020000de指的是该表里具体的那个被修改的数据行所在段里的数据块的地址
--ncol:2指的是该被修改的表有几列
nnew:1指的是该被修改的表的一行实际被修改了几列
--rci0x23,且rdba:0x00000000,表示回滚记录都在此块儿上面(应该说是上回滚记录在此undo块儿上面);如果rdba非0,那就代表回滚链中前一个块所在的位置(或者说如果rdba非0,那rdba值就代表回滚链中前一个undo记录所在的undo块的地址位置)
我们可以根据它的值再dump相关block查看。
--col1:[6]4f5241434c45,就是我做最后一次update的前镜像
附加:
若一个事务产生了五万条undo记录,一个undo块的空间一般是放不下五万条undo记录的,所以这个五万条记录会分布在不同的undo块(这几个undo块不是说要连续放在一起的,随机的)上,那么这个事务对应的事务槽上的uba字段的地址是指向哪个undo记录的呢?
一个DML操作对应会产生一个undo记录,一个包含多个DML操作的事务,其对应的事务槽上的uba字段的地址都是指向该事务里最后一个DML操作所对应的undo记录的地址的(undo块中irb指的就是这个uba地址的第三部分,即REC部分)。无论这个事务对应产生的undo记录是放在一个undo块上,还是多个undo块上,都是这样的。
一个事务对应产生的多个undo记录是如何组织在一起的呢?
就是通过undochain。
回滚链(undochain)就是指一个事务里的先后产生的多个DML操作对应的undo记录由后指向前组成的(以undo记录里的rci为指针将这几个记录连接在一起的)。
如何判断在undochain上的上一个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块前先复制一个当前块的副本,在这个副本进行还原。
相关文章推荐
- 关于web开发中静态资源缓存机制的总结
- 关于PHP的错误机制总结
- 关于JS解析机制、作用域的一些总结
- 关于纠错机制的一点总结
- 关于maemo Desktop/HomeUI自己收集的资料总结
- 关于Java反射机制的总结
- 关于K8s集群器日志收集的总结
- 关于K8s集群器日志收集的总结
- 关于java类装载机制一些总结
- 第十三天 :关于java中垃圾回收机制的总结
- 关于java初学的一些笔记总结(收集+总结)与大家分享,关于自学java,有好的建议可以回帖。
- 关于索引的总结[收集中]
- 关于事件监听机制的总结(Listener和Adapter)
- 关于java初学的一些笔记总结(收集+总结)与大家分享,关于自学java,有好的建议可以回帖。
- 关于Python并发机制的一些总结
- oracle提供的关于数值或字符与其用于实际存储到硬盘上的编码值间以及不同进制的数值间的转化方法的总结[收集中]
- 关于nginx反向代理传输机制的总结
- Java同步机制收集总结--synchronized
- 关于Android中View的分发机制的学习总结(View篇)
- JVM垃圾回收机制总结(3) :按代垃圾收集器