步骤一、先准备测试表
SQL> create table test as select * from dba_objects;
表已创建。
步骤二、分别更新两个数据块的三条记录,每更新一条提交一次。目的是为了在数据块的itl slot中插入几条记录。可以通过包dbms_rowid来获得数据块信息。
SQL>select dbms_rowid.ROWID_RELATIVE_FNO(rowid) fn, dbms_rowid.rowid_block_number(rowid) bl, test.object_id from test where rownum<200;
FN BL OBJECT_ID
--- ---------- ----------
4 1012 32
4 1012 22
4 1012 49
4 1012 30
FN BL OBJECT_ID
--- ---------- ----------
4 1013 119
4 1013 120
4 1013 121
4 1013 122
SQL> update test set object_id=3 where object_id=32;
已更新 1 行。
SQL> commit;
提交完成。
其余省略
注意这两个数据块的第四个记录暂不更新,只更新每个数据块的前三条记录,并且每更新一条,提交一次(有点墨迹啊。。)。
步骤三、dump出这两个数据块的内容,保存itl信息为后续步骤服务。
SQL> alter system dump datafile 4 block 1012;
系统已更改。
SQL> alter system dump datafile 4 block 1013;
系统已更改。
数据块1012的itl信息。
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0001.025.0000015d 0x008009cf.00bf.03 --U- 1 fsc 0x0000.000ca086
0x02 0x0004.01a.00000149 0x008000e5.0121.06 --U- 1 fsc 0x0000.000ca081
数据块1013的itl信息。
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x000a.021.00000148 0x00800153.00cb.04 --U- 1 fsc 0x0001.000ca091
0x02 0x0003.012.00000156 0x008000ce.0129.06 --U- 1 fsc 0x0001.000ca08d
步骤四、一个事务里更新两个数据块的第四条记录,不提交。
SQL> update test set object_id=3 where object_id=30;
已更新 1 行。
SQL> update test set object_id=3 where object_id=122;
已更新 1 行。
步骤五、查看v$transaction视图,获得事务信息。
SQL> select xidusn,xidslot,xidsqn,ubablk,ubafil,ubarec from v$transaction;
XIDUSN XIDSLOT XIDSQN UBABLK UBAFIL UBAREC
---------- ---------- ---------- ---------- ---------- ----------
6 45 346 980 2 31
可以看出占用的是6号回滚段,45号事务槽。占用的回滚块是2号文件,980号块。
步骤六、把回滚段头和回滚块dump出来。仅列出重点内容。部分内容省略。
SQL> alter system dump undo header '_SYSSMU6$';
系统已更改。
SQL> alter system dump datafile 2 block 980;
系统已更改。
回滚段头的dump内容:
********************************************************************************
Undo Segment: _SYSSMU6$ (6)
********************************************************************************
Extent Control Header
-----------------------------------------------------------------
TRN CTL:: seq: 0x0134 chd: 0x0020 ctl: 0x002e inc: 0x00000000 nfb: 0x0000
mgc: 0x8201 xts: 0x0068 flg: 0x0001 opt: 2147483646 (0x7ffffffe)
uba: 0x008003d4.0134.1e scn: 0x0000.000c99cf
TRN TBL::
index state cflags wrap# uel scn dba parent-xid nub stmt_num cmt
------------------------------------------------------------------------------------------------
0x00 9 0x00 0x015b 0x002e 0x0000.000ca098 0x008003d4 0x0000.000.00000000 0x00000001 0x00000000 1289970123
0x2d 10 0x80 0x015a 0x0002 0x0000.000ca091 0x008003d4 0x0000.000.00000000 0x00000001 0x00000000 0
index列代表事务槽号,state列,9代表没有活动事务,10代表活动事务。dba代表占用undo块地址。从上面可以看出45号(0x2d)事务槽上有活动事务,跟v$transaction中的信息一致。0x2d转换为十进制是45,0x008003d4 转换为2号文件 980块。转换函数如下:
CREATE OR REPLACE FUNCTION getbfno (p_dba IN VARCHAR2)
RETURN VARCHAR2
IS
l_str VARCHAR2 (255) DEFAULT NULL;
BEGIN
l_str :=
'datafile# is:'
|| DBMS_UTILITY.data_block_address_file (TO_NUMBER (LTRIM (p_dba, '0x'),'xxxxxxxx'))
|| chr(10)||'datablock is:'
|| DBMS_UTILITY.data_block_address_block (TO_NUMBER (LTRIM (p_dba, '0x'),'xxxxxxxx'));
RETURN l_str;
END;
/
SQL> select getbfno('0x008003d4') from dual;
GETBFNO('0X008003D4')
--------------------------------------------------
datafile# is:2
datablock is:980
回滚块dump的内容:
********************************************************************************
UNDO BLK:
xid: 0x0006.02d.0000015a seq: 0x134 cnt: 0x1f irb: 0x1f icl: 0x0 flg: 0x0000
Rec Offset Rec Offset Rec Offset Rec Offset Rec Offset
---------------------------------------------------------------------------
0x01 0x1f4c 0x02 0x1ea4 0x03 0x1e00 0x04 0x1d80 0x05 0x1cf8
0x06 0x1c18 0x07 0x1bb4 0x08 0x1b60 0x09 0x1a80 0x0a 0x1a1c
0x0b 0x19c8 0x0c 0x18f8 0x0d 0x1878 0x0e 0x17f8 0x0f 0x1760
0x10 0x1710 0x11 0x1690 0x12 0x160c 0x13 0x158c 0x14 0x14bc
0x15 0x13dc 0x16 0x1378 0x17 0x1324 0x18 0x12a0 0x19 0x123c
0x1a 0x118c 0x1b 0x110c 0x1c 0x1084 0x1d 0x0ff0 0x1e 0x0f40
0x1f 0x0ed8
*-----------------------------
* Rec #0x1e slt: 0x2d objn: 51447(0x0000c8f7) objd: 51448 tblspc: 4(0x00000004)
* Layer: 11 (Row) opc: 1 rci 0x00
Undo type: Regular undo Begin trans Last buffer split: No
Temp Object: No
Tablespace Undo: No
rdba: 0x00000000
*-----------------------------
uba: 0x008003d4.0134.1d ctl max scn: 0x0000.000c99aa prv tx scn: 0x0000.000c99cf
txn start scn: scn: 0x0000.00000000 logon user: 54
prev brb: 8389585 prev bcl: 0
KDO undo record:
KTB Redo
op: 0x04 ver: 0x01
op: L itl: xid: 0x0004.01a.00000149 uba: 0x008000e5.0121.06
flg: C--- lkc: 0 scn: 0x0000.000ca081
Array Update of 1 rows:
tabn: 0 slot: 42(0x2a) flag: 0x2c lock: 0 ckix: 8
ncol: 13 nnew: 1 size: 0
KDO Op code: 21 row dependencies Disabled
xtype: XAxtype KDO_KDOM2 flags: 0x00000080 bdba: 0x010003f4 hdba: 0x010003f3
itli: 2 ispac: 0 maxfr: 4858
vect = 13
col 3: [ 2] c1 1f
*-----------------------------
* Rec #0x1f slt: 0x2d objn: 51447(0x0000c8f7) objd: 51448 tblspc: 4(0x00000004)
* Layer: 11 (Row) opc: 1 rci 0x1e
Undo type: Regular undo Last buffer split: No
Temp Object: No
Tablespace Undo: No
rdba: 0x00000000
*-----------------------------
KDO undo record:
KTB Redo
op: 0x04 ver: 0x01
op: L itl: xid: 0x0003.012.00000156 uba: 0x008000ce.0129.06
flg: C--- lkc: 0 scn: 0x0000.000ca08d
KDO Op code: URP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x010003f5 hdba: 0x010003f3
itli: 2 ispac: 0 maxfr: 4858
tabn: 0 slot: 28(0x1c) flag: 0x2c lock: 0 ckix: 0
ncol: 13 nnew: 1 size: 1
col 3: [ 3] c2 02 17
dump文件里有一个参数irb: 0x1f,irb指的是回滚段中记录的最近未提交变更开始之处,如果开始回滚,这是起始的搜索点。我们从dump文件中找到0x1f。col 3: [ 3] c2 02 17代表的就是122,这是最后更新记录的前镜像。ORACLE就这样回滚保留前镜像信息的。这里还有个参数rci,该参数代表就是undo chain的下一个偏移量,这里为0x1e,我们再找到0x1e这条undo记录。col 3: [ 2] c1 1f记录的就是我们的第一条更新的数据。ORACLE通过rci把这些UNDO记录串成链,直到rci为0X00代表已经达到事务的第一条记录。
这些op: L itl: xid: 0x0003.012.00000156 uba: 0x008000ce.0129.06
flg: C--- lkc: 0 scn: 0x0000.000ca08d
代表覆盖的数据块的itl的信息。是非常重要的数据结构。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/22034023/viewspace-678324/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/22034023/viewspace-678324/
本文详细解析了Oracle数据库中如何通过回滚段保留事务的前镜像信息,包括使用SQL命令创建测试表、更新数据块记录,以及利用系统命令dump出数据块和回滚段信息等关键步骤。

被折叠的 条评论
为什么被折叠?



