Oracle undo 镜像数据探究
今天是2013-08-18,隔别一周的网络终于可以上网了。幸福啊。
我们都知道,undo是为了保证一致性读的,也就是说你在对更改的数据但是没有提交,那么其他session是无法查看到你更改的内容的,如果对方
进行读取数据,依然是之前的数据,undo就是保存了数据的前镜像。看完我写的这篇文章之后,你就知道undo是怎么保存前镜像的以及它的内部机
制是什么。现在开始挖掘undo是怎么保存前镜像的。
1)首先更新一条数据,但是不进行commit如下:
SQL> col name for a50
SQL> select obj#,name from t where rownum<5;
OBJ# NAME
---------- --------------------------------------------------
46 I_USER1
28 Rhys1
15 RHYS20
29 RHYS3
SQL> update t set name='rhys1' where obj#=46;
1 row updated.
SQL> update t set name='rhys2' where obj#=28;
1 row updated.
SQL> update t set name='rhys3' where obj#=15;
1 row updated.
SQL> update t set name='rhys4' where obj#=29;
1 row updated.
SQL> select xidusn,xidslot,ubafil,ubablk from v$transaction;
XIDUSN XIDSLOT UBAFIL UBABLK
---------- ---------- ---------- ----------
12 7 8 1493
SQL> select * from v$rollname where usn=12;
USN NAME
---------- ------------------------------
12 _SYSSMU12_584745277$
SQL> select usn,status,curext from v$rollstat;
USN STATUS CUREXT
---------- --------------- ----------
0 ONLINE 5
11 ONLINE 4
12 ONLINE 3
13 ONLINE 2
14 ONLINE 3
15 ONLINE 2
16 ONLINE 2
17 ONLINE 14
18 ONLINE 4
19 ONLINE 3
20 ONLINE 2
11 rows selected.
SQL> select usn,status,curext,xacts from v$rollstat where xacts>0;
USN STATUS CUREXT XACTS
---------- --------------- ---------- ----------
12 ONLINE 3 1
SQL> alter system dump undo header '_SYSSMU12_584745277$';
System altered.
SQL> alter system dump datafile 8 block 1493;
System altered.
SQL> col name for a80
SQL> col inst_id for 9999
SQL> col value for a80
SQL> select * from v$diag_info;
INST_ID NAME VALUE
------- -------------------------------------------------------------------------------- --------------------------------------------------------------------------------
1 Diag Enabled TRUE
1 ADR Base /opt/app/oracle
1 ADR Home /opt/app/oracle/diag/rdbms/rhys/RHYS
1 Diag Trace /opt/app/oracle/diag/rdbms/rhys/RHYS/trace
1 Diag Alert /opt/app/oracle/diag/rdbms/rhys/RHYS/alert
1 Diag Incident /opt/app/oracle/diag/rdbms/rhys/RHYS/incident
1 Diag Cdump /opt/app/oracle/diag/rdbms/rhys/RHYS/cdump
1 Health Monitor /opt/app/oracle/diag/rdbms/rhys/RHYS/hm
1 Default Trace File /opt/app/oracle/diag/rdbms/rhys/RHYS/trace/RHYS_ora_5284.trc
1 Active Problem Count 1
1 Active Incident Count 1
11 rows selected.
2)从以上步骤中,我们可以获得的信息如下:
该事务使用的undo段为12,其区为3
undo段的名字为“_SYSSMU12_584745277$”
该事务在undo的第7个槽位,数据文件号为8,使用的数据块为1493;
3)我们开始挖掘undo内部机制,首先转储undo header;(摘录信息如下)
********************************************************************************
Undo Segment: _SYSSMU12_584745277$ (12)
********************************************************************************
Extent Control Header
-----------------------------------------------------------------
Extent Header:: spare1: 0 spare2: 0 #extents: 4 #blocks: 271
last map 0x00000000 #maps: 0 offset: 4080
Highwater:: 0x020005d5 ext#: 3 blk#: 85 ext size: 128
#blocks in seg. hdr's freelists: 0
#blocks below: 0
mapblk 0x00000000 offset: 3
Unlocked
Map Header:: next 0x00000000 #extents: 4 obj#: 0 flag: 0x40000000
Extent Map
-----------------------------------------------------------------
0x02000091 length: 7
0x02000168 length: 8
0x02000280 length: 128
0x02000580 length: 128
Retention Table
-----------------------------------------------------------
Extent Number:0 Commit Time: 1376748046
Extent Number:1 Commit Time: 1376748092
Extent Number:2 Commit Time: 1376804143
Extent Number:3 Commit Time: 1376804143
TRN CTL:: seq: 0x033a chd: 0x0020 ctl: 0x0001 inc: 0x00000000 nfb: 0x0000
mgc: 0xb000 xts: 0x0068 flg: 0x0001 opt: 2147483646 (0x7ffffffe)
uba: 0x020005d5.033a.24 scn: 0x0000.009b9276
Version: 0x01
FREE BLOCK POOL::
uba: 0x00000000.033a.23 ext: 0x3 spc: 0xc78
uba: 0x00000000.033a.27 ext: 0x3 spc: 0xb20
uba: 0x00000000.033a.08 ext: 0x3 spc: 0x1c66
uba: 0x00000000.033a.45 ext: 0x3 spc: 0x200
uba: 0x00000000.0000.00 ext: 0x0 spc: 0x0
TRN TBL::
index state cflags wrap# uel scn dba parent-xid nub stmt_num cmt
------------------------------------------------------------------------------------------------
0x00 9 0x00 0x0059 0x0016 0x0000.009b9292 0x020005d3 0x0000.000.00000000 0x00000001 0x00000000 1376806203
0x01 9 0x00 0x005a 0xffff 0x0000.009b94e5 0x020005d5 0x0000.000.00000000 0x00000001 0x00000000 1376806887
0x02 9 0x00 0x005a 0x000a 0x0000.009b9461 0x020005d5 0x0000.000.00000000 0x00000001 0x00000000 1376806707
0x03 9 0x00 0x0059 0x0017 0x0000.009b930e 0x020005d3 0x0000.000.00000000 0x00000001 0x00000000 1376806203
0x04 9 0x00 0x0059 0x0005 0x0000.009b92cf 0x020005d3 0x0000.000.00000000 0x00000001 0x00000000 1376806203
0x05 9 0x00 0x0059 0x0008 0x0000.009b92d8 0x020005d3 0x0000.000.00000000 0x00000001 0x00000000 1376806203
0x06 9 0x00 0x0059 0x0009 0x0000.009b92aa 0x020005d3 0x0000.000.00000000 0x00000001 0x00000000 1376806203
0x07 10 0x80 0x005a 0x0003 0x0000.00000000 0x020005d5 0x0000.000.00000000 0x00000001 0x00000000 0
0x08 9 0x00 0x0059 0x001b 0x0000.009b92e1 0x020005d3 0x0000.000.00000000 0x00000001 0x00000000 1376806203
0x09 9 0x00 0x0059 0x000c 0x0000.009b92b6 0x020005d3 0x0000.000.00000000 0x00000001 0x00000000 1376806203
0x0a 9 0x00 0x0059 0x001f 0x0000.009b9479 0x020005d5 0x0000.000.00000000 0x00000001 0x00000000 1376806707
0x0b 9 0x00 0x0059 0x001a 0x0000.009b92fc 0x020005d3 0x0000.000.00000000 0x00000001 0x00000000 1376806203
0x0c 9 0x00 0x0059 0x0004 0x0000.009b92c3 0x020005d3 0x0000.000.00000000 0x00000001 0x00000000 1376806203
可以看到在事务表中0x07正是第七个slot,把dba转为2进制,在转为10进制,可以打出数据文件号为8,数据块为1493,这正是数据的前镜像。
4)我们已经在 undo header中找到了数据的前镜像,那么我们在看一下这个前镜像到底是什么?
摘录数据文件信息如下:
********************************************************************************
UNDO BLK:
xid: 0x000c.007.0000005a seq: 0x33a cnt: 0x27 irb: 0x27 icl: 0x0 flg: 0x0000
Rec Offset Rec Offset Rec Offset Rec Offset Rec Offset
---------------------------------------------------------------------------
0x01 0x1f4c 0x02 0x1ec4 0x03 0x1db0 0x04 0x1d3c 0x05 0x1cb8
0x06 0x1c4c 0x07 0x1be8 0x08 0x1b94 0x09 0x1aec 0x0a 0x1a4c
0x0b 0x19ac 0x0c 0x1900 0x0d 0x1854 0x0e 0x17ac 0x0f 0x171c
0x10 0x167c 0x11 0x15d4 0x12 0x1544 0x13 0x14a4 0x14 0x13f8
0x15 0x139c 0x16 0x1328 0x17 0x128c 0x18 0x117c 0x19 0x1114
0x1a 0x10bc 0x1b 0x1068 0x1c 0x100c 0x1d 0x0f98 0x1e 0x0f3c
0x1f 0x0ee8 0x20 0x0e60 0x21 0x0dd4 0x22 0x0d6c 0x23 0x0cd0
0x24 0x0c2c 0x25 0x0bb0 0x26 0x0b50 0x27 0x0ad4
可以看到数据记录为39,这是第一条,并且最后一个偏移量也为39,这正是rollback的开始。
*-----------------------------
* Rec #0x27 slt: 0x07 objn: 73229(0x00011e0d) objd: 73229 tblspc: 0(0x00000000)
* Layer: 11 (Row) opc: 1 rci 0x26
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: 0x020005d5.033a.26
Array Update of 1 rows:
tabn: 0 slot: 109(0x6d) flag: 0x2c lock: 0 ckix: 0
ncol: 18 nnew: 1 size: 0
KDO Op code: 21 row dependencies Disabled
xtype: XAxtype KDO_KDOM2 flags: 0x00000080 bdba: 0x0041e7f4 hdba: 0x00414908
itli: 1 ispac: 0 maxfr: 4863
vect = 8
col 3: [ 5] 52 48 59 53 33
好了,既然找到了,那么我们看一下这条record记录了是数据的是什么.
前镜像为:RHYS3
SQL>
这是最后一条SQL> update t set name='rhys4' where obj#=29;的前镜像。因为 开始部分是从倒叙的,因此,我们在看倒数第二条。
*-----------------------------
* Rec #0x26 slt: 0x07 objn: 73229(0x00011e0d) objd: 73229 tblspc: 0(0x00000000)
* Layer: 11 (Row) opc: 1 rci 0x25
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: 0x020005d5.033a.25
KDO Op code: URP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x0041e7f4 hdba: 0x00414908
itli: 1 ispac: 0 maxfr: 4863
tabn: 0 slot: 108(0x6c) flag: 0x2c lock: 0 ckix: 0
ncol: 18 nnew: 1 size: 1
col 3: [ 6] 52 48 59 53 32 30
前镜像为:
SQL> select utl_raw.cast_to_varchar2(replace('52 48 59 53 32 30',' ') ) nam from dual;
NAM
--------------------------------------------------------------------------------
RHYS20
SQL>
第三条语句:
*-----------------------------
* Rec #0x25 slt: 0x07 objn: 73229(0x00011e0d) objd: 73229 tblspc: 0(0x00000000)
* Layer: 11 (Row) opc: 1 rci 0x24
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: 0x020005d5.033a.24
Array Update of 1 rows:
tabn: 0 slot: 107(0x6b) flag: 0x2c lock: 0 ckix: 0
ncol: 18 nnew: 1 size: 0
KDO Op code: 21 row dependencies Disabled
xtype: XAxtype KDO_KDOM2 flags: 0x00000080 bdba: 0x0041e7f4 hdba: 0x00414908
itli: 1 ispac: 0 maxfr: 4863
vect = 8
col 3: [ 5] 52 68 79 73 31
前镜像为:Rhys1
在看第四条:
*-----------------------------
* Rec #0x24 slt: 0x07 objn: 73229(0x00011e0d) objd: 73229 tblspc: 0(0x00000000)
* 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: 0x020005d5.033a.23 ctl max scn: 0x0000.009b926d prv tx scn: 0x0000.009b9276
txn start scn: scn: 0x0000.009b950d logon user: 0
prev brb: 33555923 prev bcl: 0
KDO undo record:
KTB Redo
op: 0x04 ver: 0x01
compat bit: 4 (post-11) padding: 1
op: L itl: xid: 0x0011.00d.0000003e uba: 0x02000230.01ee.3a
flg: C--- lkc: 0 scn: 0x0000.009b4ab6
KDO Op code: URP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x0041e7f4 hdba: 0x00414908
itli: 1 ispac: 0 maxfr: 4863
tabn: 0 slot: 106(0x6a) flag: 0x2c lock: 0 ckix: 0
ncol: 18 nnew: 1 size: 2
col 3: [ 7] 49 5f 55 53 45 52 31
前镜像为:I_USER1
至此,在回过头来,看看 刚刚开始update的数据。
SQL> select obj#,name from t where rownum<5;
OBJ# NAME
---------- --------------------------------------------------
46 I_USER1
28 Rhys1
15 RHYS20
29 RHYS3
SQL> update t set name='rhys1' where obj#=46;
1 row updated.
SQL> update t set name='rhys2' where obj#=28;
1 row updated.
SQL> update t set name='rhys3' where obj#=15;
1 row updated.
SQL> update t set name='rhys4' where obj#=29;
1 row updated.
oracle,就是这样存储数据前镜像的。哈哈。
继续研究,然后拿出undo record的一条记录如下:
*-----------------------------
* Rec #0x24 slt: 0x07 objn: 73229(0x00011e0d) objd: 73229 tblspc: 0(0x00000000)
* 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: 0x020005d5.033a.23 ctl max scn: 0x0000.009b926d prv tx scn: 0x0000.009b9276
txn start scn: scn: 0x0000.009b950d logon user: 0
prev brb: 33555923 prev bcl: 0
KDO undo record:
KTB Redo
op: 0x04 ver: 0x01
compat bit: 4 (post-11) padding: 1
op: L itl: xid: 0x0011.00d.0000003e uba: 0x02000230.01ee.3a
flg: C--- lkc: 0 scn: 0x0000.009b4ab6
KDO Op code: URP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x0041e7f4 hdba: 0x00414908
itli: 1 ispac: 0 maxfr: 4863
tabn: 0 slot: 106(0x6a) flag: 0x2c lock: 0 ckix: 0
ncol: 18 nnew: 1 size: 2
col 3: [ 7] 49 5f 55 53 45 52 31
可以看到在record中也记录了该undo对应的前镜像的数据块的地址信息,bdba。
我们进行转换得到:0000000001 0000011110011111110100 可以得到是file 1,block 124916.
可以断定该表存在于system,如下:
SQL> col file_name for a70
SQL> select a.table_name,a.tablespace_name,b.file_name from user_tables a,dba_data_files b where a.tablespace_name=b.tablespace_name and a.table_name='T';
TABLE_NAME TABLESPACE_NAME FILE_NAME
------------------------------ -------------------- ----------------------------------------------------------------------
T SYSTEM /opt/app/oracle/RHYS/system01.dbf
SQL>
然后,在跟随盖老师,看一下system01.dbf这个数据文件内容信息。转储信息如下:
Block header dump: 0x0041e7f4
Object id on Block? Y
seg/obj: 0x11e0d csc: 0x00.9bb647 itc: 2 flg: O typ: 1 - DATA
fsl: 0 fnx: 0x41e7f3 ver: 0x01
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x000c.007.0000005a 0x020005d5.033a.27 ---- 4 fsc 0x0003.00000000
0x02 0x0014.001.00000044 0x02000628.037b.06 C--- 0 scn 0x0000.009b94a8
bdba: 0x0041e7f4
data_block_dump,data header at 0x7f6e9e263a5c
当我们修改数据的时候会对相应的数据加锁,更直接说该 锁存在于数据块中,并且存在itl(事务槽信息),可以现在数据块中itl的详细内容了
其中包括xid,uba,flag,lock status,scn
xid代表事务id,其中包括undo段号,槽位号,wrap,然后我们转换一下该xid,可以看到undo.segment.number 为12,占用的槽位是7,wrap#为:90
我们查看一下事务视图进行一下确认。
1* select xidusn,xidslot,xid,name,ubasqn,ubarec,ubafil,ubablk from v$transaction where xidusn=12
XIDUSN XIDSLOT XID NAME UBASQN UBAREC UBAFIL UBABLK
---------- ---------- ---------------- ---------- ---------- ---------- ---------- ----------
12 7 0C0007005A000000 826 39 8 1493
SQL>
然后摘录一下undo header事务表部分如下:
0x07 10 0x80 0x005a 0x0003 0x0000.00000000 0x020005d5 0x0000.000.00000000 0x00000001 0x00000000 0
然后我们在看一下 这个事务的信息;
eg:
SQL> select xid,start_scn,commit_scn,operation,table_name,row_id,undo_sql from flashback_transaction_query where xid='0C0007005A000000';
XID START_SCN COMMIT_SCN OPERATION TABLE_NAME ROW_ID UNDO_SQL
---------------- ---------- ---------- -------------------------------- -------------------------------------------------------------------------------- ------------------- --------------------------------------------------------------------------------
0C0007005A000000 10196237 UNKNOWN T
0C0007005A000000 10196237 UNKNOWN T
0C0007005A000000 10196237 UNKNOWN T
0C0007005A000000 10196237 UNKNOWN T
0C0007005A000000 10196237 BEGIN
SQL>
为什么undo_sql没有信息呢?我想是没有commit。稍后再看。
在数据块中的itl中存在一个uba,这正是该数据的前镜像信息。0x020005d5.033a.27转换一下,为20005d5(前镜像地址),033a为事务sequence号,
27为irb
如:
********************************************************************************
UNDO BLK:
xid: 0x000c.007.0000005a seq: 0x33a cnt: 0x27 irb: 0x27 icl: 0x0 flg: 0x0000
貌似有点乱,整理一下思路。
当执行个update语句的时候,首先在segment上分配段分配slot,然后再数据块头部记录itl信息指向undo record,undo record记录了数据的前镜像,
并且从最后一个记录开始到第一个执行update语句,这是一个倒叙研究查看过程,随后在数据块itl中存储锁信息,指定该数据块状态。然后再修改数据。
对了,现在看一下数据块锁的信息:
eg:
SQL> SELECT * FROM V$MYSTAT WHERE ROWNUM<2;
SID STATISTIC# VALUE
---------- ---------- ----------
1 0 0
SQL>
SQL> select a.sid,a.lmode,a.id1,b.type,b.name,b.description from v$lock a,v$lock_type b where a.sid=1 and a.type=b.type;
SID LMODE ID1 TYPE NAME DESCRIPTION
---------- ---------- ---------- ---------------------------------------------------------------- ---------------------------------------------------------------- --------------------------------------------------------------------------------
1 4 100 AE Edition Lock Prevent Dropping an edition in use
1 3 73229 TM DML Synchronizes accesses to an object
1 6 786439 TX Transaction Lock held by a transaction to allow other transactions to wait for it
SQL>
在数据块中的itl中锁的状态为3.代表Prevent Dropping an edition in use。
好了。就到 这把,另外在undo中也存有rdba信息,在学习redo的时候会进行联系,深入。