Oracle UNDO块
过程:开始一个事务--通过事务信息找到UNDO块头的所在的段名及数据文件号等--转储UNDO header--在事务表中对应槽位找到前镜像dba--转储数据块--找到对应记录得到bdba--转储数据块
1)首先更新几条数据,但是不进行commit如下:
SYS@ prod>select * from scott.emp; EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO ---------- ---------- --------- ---------- ------------------- ---------- ---------- ---------- 7369 SMITH CLERK 7902 1980-12-17 00:00:00 800 20 7499 ALLEN SALESMAN 7698 1981-02-20 00:00:00 1600 300 30 7521 WARD SALESMAN 7698 1981-02-22 00:00:00 1250 500 30 7566 JONES MANAGER 7839 1981-04-02 00:00:00 2975 20 7654 MARTIN SALESMAN 7698 1981-09-28 00:00:00 1250 1400 30 SYS@ prod>update scott.emp set sal=2000 where empno='7369'; 1 row updated. SYS@ prod>update scott.emp set sal=2001 where empno='7499'; 1 row updated. SYS@ prod>update scott.emp set sal=2002 where empno='7521'; 1 row updated. SYS@ prod>update scott.emp set sal=2003 where empno='7566'; 1 row updated.
2)v$transaction列出活动事务相关信息
SYS@ prod>select xidusn,xidslot,ubafil,ubablk from v$transaction; XIDUSN XIDSLOT UBAFIL UBABLK ---------- ---------- ---------- ---------- 11 25 6 12
XIDUSN:Undo segment number
XIDSLOT:Slot number
UBAFIL:Undo block address(UBA) filenum
UBABLK:UBA block number
该事务使用的undo段号为11,该事务在undo的第25个槽位,数据文件号为6,使用的数据块为12;
3)V$ROLLNAME列出所有在线回滚段。只能在数据库打开时访问。
SYS@ prod>select * from v$rollname where usn=11; USN NAME ---------- ------------------------------ 11 _SYSSMU11_1796584641$
NAME:Rollback segment name
undo段号为11,名字为 _SYSSMU11_1796584641$
4)V$ROLLSTAT包含回滚段信息。
SYS@ prod>select usn,status,curext,xacts from v$rollstat; USN STATUS CUREXT XACTS ---------- --------------- ---------- ---------- 0 ONLINE 1 0 11 ONLINE 0 1
USN:Rollback segment number
STATUS:Rollback segment status:ONLINE/PENDING OFFLINE/OFFLINE/FULL
CUREXT:Current extent
XACTS:Number of active transactions
undo段号为11,在线,区号为0,1个活动事务
4)转储undo header
SYS@ prod>alter system dump undo header '_SYSSMU11_1796584641$'; System altered.
5)查看默认trace文件位置
SYS@ prod>col value for a50 SYS@ prod>select * from v$diag_info; INST_ID NAME VALUE ---------- ---------------------------------------------------------------- -------------------------------------------------- 1 Diag Enabled TRUE 1 ADR Base /u01 1 ADR Home /u01/diag/rdbms/prod/prod 1 Diag Trace /u01/diag/rdbms/prod/prod/trace 1 Diag Alert /u01/diag/rdbms/prod/prod/alert 1 Diag Incident /u01/diag/rdbms/prod/prod/incident 1 Diag Cdump /u01/diag/rdbms/prod/prod/cdump 1 Health Monitor /u01/diag/rdbms/prod/prod/hm 1 Default Trace File /u01/diag/rdbms/prod/prod/trace/prod_ora_2361.trc 1 Active Problem Count 0 1 Active Incident Count 0 11 rows selected.
6)分析UDNO段头块的日志
more /u01/diag/rdbms/prod/prod/trace/prod_ora_2361.trc
********************************************************************************
Undo Segment: _SYSSMU11_1796584641$ (11)
********************************************************************************
Extent Control Header
-----------------------------------------------------------------
Extent Header:: spare1: 0 spare2: 0 #extents: 2 #blocks: 15
last map 0x00000000 #maps: 0 offset: 4080
Highwater:: 0x0180000e ext#: 0 blk#: 5 ext size: 7
#blocks in seg. hdr's freelists: 0
#blocks below: 0
mapblk 0x00000000 offset: 0
Unlocked
Map Header:: next 0x00000000 #extents: 2 obj#: 0 flag: 0x40000000
- #extents: 2 表示11号UNDO段有两个区
- #blocks: 15 表示11号UNDO回滚段两个区中有15个UNDO BLOCK可用。(为什么不是16个UNDO BLOCK块呢,去掉一个UNDO段头块)
- ext#: 0 表示这个事务发生在第1个区(从0开始)
- blk#: 5 表示这个事务发生在第1个区的第5个块上。
- ext size: 7 表示1个区上有7个UNDO BLOCK可用
7)通过dba_extents视图查出一共有两个区,共16个块
SYS@ prod>select extent_id,file_id,block_id,blocks,bytes from dba_extents where segment_name='_SYSSMU11_1796584641$'; EXTENT_ID FILE_ID BLOCK_ID BLOCKS BYTES ---------- ---------- ---------- ---------- ---------- 0 6 8 8 65536 1 6 16 8 65536
8)通过dba_segments视图查出UNDO段头块,即6号文件的8号块是UNDO段头块(所以#blocks:15)
SYS@ prod>select header_file,header_block from dba_segments where segment_name='_SYSSMU11_1796584641$'; HEADER_FILE HEADER_BLOCK ----------- ------------ 6 8
9)继续向下
Extent Map ----------------------------------------------------------------- 0x01800009 length: 7 0x01800010 length: 8
区位图:第一个区是undo块的地址为0x0180009开始的前7个块+头块;第二个区是0x0180010开始的8-16块。
10)继续向下
Retention Table ----------------------------------------------------------- Extent Number:0 Commit Time: 1552092157 Extent Number:1 Commit Time: 1552092157
区的提交时间戳,是从1970年1月1号零时开始计数(以秒为单位记录)
11)继续向下
TRN CTL:: seq: 0x0003 chd: 0x0020 ctl: 0x0000 inc: 0x00000000 nfb: 0x0001 mgc: 0xb000 xts: 0x0068 flg: 0x0001 opt: 2147483646 (0x7ffffffe) uba: 0x0180000e.0003.0c scn: 0x0000.00104372
事务控制:
seq: 0x0003 表示此事务修改前的值所在的UNDOBLOCK块被覆盖了3次,与第三行的uba:0x0180000f.0003.08中的0003对应。
chd:0x0020 表示发生一个新的事务,此时会在下面的TRNTBL::(事务表)的index=0x00020槽中放入新事务信息,即事务表的链头或叫入口。
ctl: 0x0000 表示事务表的链尾(实际上大家可以去TRN TBL::看index=0x0000,它对应的SCN=0x0000.00104485是本事务表中最大的SCN,即此事务槽最后才会被覆盖)
nfb: 0x0001 表示UNDO块在空闲池的空闲块数,0x0000表示池中没有空闲UNDO块了,即FREE BLOCKPOOL::没空闲的块了。
flg: 0x0001 表示该块的用途,1=KTUUNDO HEADER(2=KTU UNDO BLOCK等等)
uba: 0x0180000e.0003.0c 表示新事务的第一条UNDO记录(由三部分组成undo块的地址、UNDO块被重用的次数、在UNDO块的第几条记录)。
- UNDO块的地址:0x0180000e即6号文件的14号块(把0x0180000e 转为2进制,前10为文件号,后22位为块号,转换为10进制可得数据文件号为6,数据块为14)。
- UNDO块被重用的次数: 0003 即UNDO块被覆盖了3次
- 在UNDO块的第几条记录 0c 即在UNDO块的第12条
- scn: 0x0000.00104372 表示11号UNDO段头块中最小的提交的SCN。实际上这个SCN就是事务表中最小的SCN所对应的事务槽上的SCN
12)继续向下
FREE BLOCK POOL:: uba: 0x0180000e.0003.0e ext: 0x0 spc: 0x183a uba: 0x00000000.0003.19 ext: 0x0 spc: 0x10c0 uba: 0x00000000.0001.0e ext: 0x0 spc: 0x18a2 uba: 0x00000000.0000.00 ext: 0x0 spc: 0x0 uba: 0x00000000.0000.00 ext: 0x0 spc: 0x0
UNDO块的空闲池,当事务做了提交会把此事务所在的UNDO块加入空闲池中。
uba: 由三部分组成undo块的地址、UNDO块被重用的次数、在UNDO块的第几条记录,当undo块的地址为0说明UNDO块不是空闲的,即0x00000000
ext: UNDO块是在哪个区(extent)
spc: UNDO块中多少空闲空间,单位字节 从上面的UNDO空闲池中看,没有空闲的UNDO块。
13)事物表
TRN TBL:: index state cflags wrap# uel scn dba parent-xid nub stmt_num cmt ------------------------------------------------------------------------------------------------ 0x00 9 0x00 0x000b 0xffff 0x0000.00104485 0x0180000e 0x0000.000.00000000 0x00000001 0x00000000 1552092317 0x01 9 0x00 0x000a 0x001a 0x0000.001043f3 0x0180000c 0x0000.000.00000000 0x00000001 0x00000000 1552092190 0x02 9 0x00 0x000a 0x0021 0x0000.00104374 0x0180000c 0x0000.000.00000000 0x00000001 0x00000000 1552092173 0x03 9 0x00 0x000a 0x000c 0x0000.0010440a 0x00000000 0x0000.000.00000000 0x00000000 0x00000000 1552092191 0x04 9 0x00 0x000a 0x0001 0x0000.00104376 0x0180000c 0x0000.000.00000000 0x00000001 0x00000000 1552092173 0x05 9 0x00 0x000a 0x000a 0x0000.00104403 0x0180000d 0x0000.000.00000000 0x00000001 0x00000000 1552092191 0x06 9 0x00 0x000a 0x0007 0x0000.001043fe 0x0180000d 0x0000.000.00000000 0x00000001 0x00000000 1552092191 0x07 9 0x00 0x000a 0x0008 0x0000.00104400 0x0180000d 0x0000.000.00000000 0x00000001 0x00000000 1552092191 0x08 9 0x00 0x000a 0x0005 0x0000.00104402 0x0180000d 0x0000.000.00000000 0x00000001 0x00000000 1552092191 0x09 9 0x00 0x000a 0x0003 0x0000.00104407 0x0180000d 0x0000.000.00000000 0x00000001 0x00000000 1552092191 0x0a 9 0x00 0x000a 0x0009 0x0000.00104404 0x0180000d 0x0000.000.00000000 0x00000001 0x00000000 1552092191 0x0b 9 0x00 0x000a 0x000e 0x0000.0010440f 0x0180000d 0x0000.000.00000000 0x00000001 0x00000000 1552092191 0x0c 9 0x00 0x000a 0x000b 0x0000.0010440c 0x0180000d 0x0000.000.00000000 0x00000001 0x00000000 1552092191 0x0d 9 0x00 0x000a 0x0010 0x0000.00104414 0x0180000d 0x0000.000.00000000 0x00000001 0x00000000 1552092191 0x0e 9 0x00 0x000a 0x000d 0x0000.00104411 0x0180000d 0x0000.000.00000000 0x00000001 0x00000000 1552092191 0x0f 9 0x00 0x000a 0x0012 0x0000.0010441e 0x0180000d 0x0000.000.00000000 0x00000001 0x00000000 1552092191 0x10 9 0x00 0x000a 0x000f 0x0000.0010441a 0x0180000d 0x0000.000.00000000 0x00000001 0x00000000 1552092191 0x11 9 0x00 0x000a 0x0013 0x0000.00104420 0x0180000d 0x0000.000.00000000 0x00000001 0x00000000 1552092191 0x12 9 0x00 0x0009 0x0011 0x0000.0010441f 0x0180000d 0x0000.000.00000000 0x00000001 0x00000000 1552092191 0x13 9 0x00 0x000a 0x0014 0x0000.00104422 0x0180000d 0x0000.000.00000000 0x00000001 0x00000000 1552092192 0x14 9 0x00 0x000a 0x0015 0x0000.00104425 0x0180000d 0x0000.000.00000000 0x00000001 0x00000000 1552092192 0x15 9 0x00 0x000a 0x0016 0x0000.00104435 0x0180000d 0x0000.000.00000000 0x00000001 0x00000000 1552092195 0x16 9 0x00 0x000a 0x0017 0x0000.00104437 0x0180000d 0x0000.000.00000000 0x00000001 0x00000000 1552092195 0x17 9 0x00 0x000a 0x0018 0x0000.00104439 0x0180000c 0x0000.000.00000000 0x00000001 0x00000000 1552092196 0x18 9 0x00 0x000a 0x001b 0x0000.0010443b 0x0180000c 0x0000.000.00000000 0x00000001 0x00000000 1552092196 0x19 10 0x80 0x000a 0x0000 0x0000.0010444f 0x0180000c 0x0000.000.00000000 0x00000001 0x00000000 0 0x1a 9 0x00 0x0009 0x0006 0x0000.001043f6 0x0180000c 0x0000.000.00000000 0x00000001 0x00000000 1552092190 0x1b 9 0x00 0x000a 0x001c 0x0000.00104454 0x0180000e 0x0000.000.00000000 0x00000001 0x00000000 1552092257 0x1c 9 0x00 0x000a 0x001d 0x0000.0010445a 0x0180000e 0x0000.000.00000000 0x00000001 0x00000000 1552092257 0x1d 9 0x00 0x000a 0x001e 0x0000.00104460 0x0180000e 0x0000.000.00000000 0x00000001 0x00000000 1552092257 0x1e 9 0x00 0x000a 0x001f 0x0000.00104479 0x0180000e 0x0000.000.00000000 0x00000001 0x00000000 1552092317 0x1f 9 0x00 0x000a 0x0000 0x0000.0010447f 0x0180000e 0x0000.000.00000000 0x00000001 0x00000000 1552092317 0x20 9 0x00 0x0009 0x0002 0x0000.00104373 0x0180000c 0x0000.000.00000000 0x00000001 0x00000000 1552092173 0x21 9 0x00 0x0009 0x0004 0x0000.00104375 0x0180000c 0x0000.000.00000000 0x00000001 0x00000000 1552092173
TRN TBL::(事务表)是UNDO段头块最重要的。我们一一来解释每个字段的意思:
index 表示事务表中槽号,只是一个序列而已,从0x00开始到0x21结束,11g的版本有34个槽。
state 表示事务状态:9代表事务不活动,10代表事务正在活动,从这里我们看出16进制第0x19号槽上的事务正在活动。在发生事务前,Oracle会找TRN CTL中的chd存放当前最新的事务。
cflags 表示正在使用事务槽的事务的状态:0x00表示非活动事务、0x80表示活动事务、0x10表示死事务、0x90表示被回滚的死事务 平时我们看到的最多就是0x00表示非活动事务、0x80表示活动事务,后面的很少发生。
wrap# 表示事务表上的事务槽被重用的次数,它是XID的一部分。0x000a表示此时事务槽被重用了10次。
uel 表示当前活动事务所在事务槽的下一个事务槽的指针(即如果又发生一个新的事务,此时就会用到UEL指向的事务槽上的index)。
scn 表示务事启动、提交、回滚的SCN.
dba 表示uba:第一部分的undo块地址,这个DBA是(rollback)回滚的起始点,也就是说是记录事务修改的最后一条记录所在UNDO块的地址。
nub 表示当前事务所用到的UNDO块的个数。
cmt 表示最接近当前的提交时间戳,是从1970年1月1号零时开始计数(以秒为单位记录)。0表示事务正在活动。
14)我们已经在 undo header中找到了数据的前镜像,那么我们在看一下这个前镜像到底是什么?
事物表中0x19槽的dba 0x0180000c即6号文件的12号块(把0x0180000c转为2进制,前10为文件号,后22位为块号,转换为10进制可得数据文件号为6,数据块为12)(与v$transaction视图中一致)。
转储数据块
SYS@ prod>alter system dump datafile 6 block 12; System altered.
******************************************************************************** UNDO BLK: xid: 0x000b.019.0000000a seq: 0x3 cnt: 0x23 irb: 0x23 icl: 0x0 flg: 0x0000 Rec Offset Rec Offset Rec Offset Rec Offset Rec Offset --------------------------------------------------------------------------- 0x01 0x1f84 0x02 0x1f20 0x03 0x1ebc 0x04 0x1e58 0x05 0x1df4 0x06 0x1d90 0x07 0x1d08 0x08 0x1bf4 0x09 0x1b8c 0x0a 0x1b34 0x0b 0x1ae0 0x0c 0x1a84 0x0d 0x1a10 0x0e 0x19b4 0x0f 0x1960 0x10 0x188c 0x11 0x17b8 0x12 0x16dc 0x13 0x15fc 0x14 0x14fc 0x15 0x13f8 0x16 0x131c 0x17 0x1238 0x18 0x1154 0x19 0x1104 0x1a 0x107c 0x1b 0x0ff0 0x1c 0x0f88 0x1d 0x0ea0 0x1e 0x0e38 0x1f 0x0de0 0x20 0x0d5c 0x21 0x0d00 0x22 0x0ca8 0x23 0x0c50
可以看到数据记录为35,这是第一条,并且最后一个偏移量0x23也为35,这正是rollback的开始。
15)继续向下
可以先查询出object_id,在trace文件中搜索
SYS@ prod>col object_name for a20 SYS@ prod>select OBJECT_NAME,OBJECT_ID,OBJECT_TYPE,CREATED from dba_objects where OBJECT_name = 'EMP'; OBJECT_NAME OBJECT_ID OBJECT_TYPE CREATED -------------------- ---------- ------------------- ------------------- EMP 73181 TABLE 2009-08-13 23:35:45
*----------------------------- * Rec #0x20 slt: 0x19 objn: 73181(0x00011ddd) objd: 73181 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: 0x00000000Ext idx: 0 flg2: 0 *----------------------------- uba: 0x0180000c.0003.1d ctl max scn: 0x0000.00104368 prv tx scn: 0x0000.0010436a txn start scn: scn: 0x0000.0010444f logon user: 0 prev brb: 25165834 prev bcl: 0 KDO undo record: KTB Redo op: 0x03 ver: 0x01 compat bit: 4 (post-11) padding: 1 op: Z KDO Op code: URP row dependencies Disabled xtype: XAxtype KDO_KDOM2 flags: 0x00000080 bdba: 0x01000097 hdba: 0x01000092 itli: 2 ispac: 0 maxfr: 4858 tabn: 0 slot: 0(0x0) flag: 0x2c lock: 0 ckix: 191 ncol: 8 nnew: 1 size: 0 Vector content: col 5: [ 2] c2 09
计算最后一行col的raw值
SYS@ prod>select utl_raw.cast_to_number(replace('C2 09',' ')) from dual; UTL_RAW.CAST_TO_NUMBER(REPLACE('C209','')) ------------------------------------------ 800
800正是更新前的值。Oracle就是这样存储数据前镜像的。
可以看到在record中也记录了该undo对应的前镜像的数据块的地址信息bdba 0x01000097。我们进行转换得到:0000000100 0000000000000010010111 可以得到是file 4,block 151。
SYS@ prod>select a.table_name,a.tablespace_name,b.file_name from dba_tables a,dba_data_files b where a.tablespace_name=b.tablespace_name and b.file_id = '4'; TABLE_NAME TABLESPACE_NAME FILE_NAME ------------------------------ ------------------------------ ---------------------------------------------------------------------- T2 USERS /u01/oradata/prod/users01.dbf T1 USERS /u01/oradata/prod/users01.dbf EMP1 USERS /u01/oradata/prod/users01.dbf TEAM USERS /u01/oradata/prod/users01.dbf CUSTOMERS USERS /u01/oradata/prod/users01.dbf DIMENSION_EXCEPTIONS USERS /u01/oradata/prod/users01.dbf SUBCATEGORY_REF_LIST_NESTEDTAB USERS /u01/oradata/prod/users01.dbf PRODUCT_REF_LIST_NESTEDTAB USERS /u01/oradata/prod/users01.dbf SALGRADE USERS /u01/oradata/prod/users01.dbf BONUS USERS /u01/oradata/prod/users01.dbf EMP USERS /u01/oradata/prod/users01.dbf DEPT USERS /u01/oradata/prod/users01.dbf 12 rows selected.
转储数据块
SYS@ prod>alter system dump datafile 4 block 151; System altered.
users01.dbf 转储信息如下:
Block header dump: 0x01000097 Object id on Block? Y seg/obj: 0x11ddd csc: 0x00.f587b itc: 2 flg: E typ: 1 - DATA brn: 0 bdba: 0x1000090 ver: 0x01 opc: 0 inc: 0 exflg: 0 Itl Xid Uba Flag Lck Scn/Fsc 0x01 0x0001.010.00000198 0x00c15ab0.0061.12 C--- 0 scn 0x0000.000b6f31 0x02 0x000b.019.0000000a 0x0180000c.0003.23 ---- 4 fsc 0x0000.00000000 bdba: 0x01000097 data_block_dump,data header at 0xe51664
当我们修改数据的时候会对相应的数据加锁,更直接说该锁存在于数据块中,并且存在itl(事务槽信息),itl的详细内容:其中包括xid,uba,flag,lock status,scn
xid代表事务id(undo段号.槽位号.wrap),其中包括undo段号0x0001=1,槽位号010=10,wrap00000198=408。等于undo块中xid
uba,这正是该数据的前镜像信息。
我们查看一下事务视图进行一下确认。
SYS@ prod>select xidusn,xidslot,xid,name,ubasqn,ubarec,ubafil,ubablk from v$transaction where xidusn=11; XIDUSN XIDSLOT XID NAME UBASQN UBAREC UBAFIL UBABLK ---------- ---------- -------------------- -------------------- ---------- ---------- ---------- ---------- 11 25 0B0019000A000000 3 35 6 12
事务的信息
SYS@ prod>select xid,start_scn,commit_scn,operation,table_name,row_id,undo_sql from flashback_transaction_query where xid='0B0019000A000000'; XID START_SCN COMMIT_SCN OPERATION TABLE_NAME ROW_ID UNDO_SQL -------------------- ---------- ---------- -------------------------------- ---------- ------------------- ---------- 0B0019000A000000 1066063 UNKNOWN EMP 0B0019000A000000 1066063 UNKNOWN EMP 0B0019000A000000 1066063 UNKNOWN EMP 0B0019000A000000 1066063 UNKNOWN EMP 0B0019000A000000 1066063 BEGIN
摘录一下undo header事务表0x19(25槽)如下
0x19 10 0x80 0x000a 0x0000 0x0000.0010444f 0x0180000c 0x0000.000.00000000 0x00000001 0x00000000 0
在数据块中的itl中存在一个uba,这正是该数据的前镜像信息。
当执行个update语句的时候,首先在segment上分配段分配slot,然后再数据块头部记录itl信息指向undo record,undo record记录了数据的前镜像,
并且从最后一个记录开始到第一个执行update语句,这是一个倒叙研究查看过程,随后在数据块itl中存储锁信息,指定该数据块状态。然后再修改数据。
现在看一下数据块锁的信息:
SYS@ prod>SELECT * FROM V$MYSTAT WHERE ROWNUM<2; SID STATISTIC# VALUE ---------- ---------- ---------- 37 0 0
SYS@ prod>col DESCRIPTION for a50 SYS@ prod>col TYPE for a20 SYS@ prod>select a.sid,a.lmode,a.id1,b.type,b.name,b.description from v$lock a,v$lock_type b where a.sid=37 and a.type=b.type; SID LMODE ID1 TYPE NAME DESCRIPTION ---------- ---------- ---------- -------------------- -------------------- -------------------------------------------------- 37 4 100 AE Edition Lock Prevent Dropping an edition in use