说明:
本文通过dump data block、undo segment header block、undo block,来理解Oracle数据库中事物槽、UNDO等工作机制。
数据库版本:
Oracle 11.2.0.4.0
创建测试数据:
create table t1(id int,name char(10)); Table created. create table t2(id int,name char(10)) INITRANS 5 MAXTRANS 100; Table created. create table t3(id int,name char(10)) INITRANS 5 MAXTRANS 256; ERROR at line 1: ORA-02209: invalid MAXTRANS option value
复制
[oracle@cjc-db-01 ~]$ oerr ora 02209 02209, 00000, "invalid MAXTRANS option value" // *Cause: The MAXTRANS value is not an integer between 1 and 255 // and greater than or equal to the INITRANS value. // *Action: Choose a valid MAXTRANS value.
复制
一个表,有1-255个事务槽,MAX_TRANS值最大255,建表时可以修改INI_TRANS。
SQL> SELECT TABLE_NAME,INI_TRANS,MAX_TRANS FROM DBA_TABLES WHERE TABLE_NAME IN ('T1','T2'); TABLE_NAME INI_TRANS MAX_TRANS ------------------------------ ---------- ---------- T1 1 255 T2 5 255
复制
插入测试数据
insert into t1 values(1,'a'); insert into t1 values(2,'b'); insert into t1 values(3,'c'); insert into t1 values(4,'d'); insert into t1 values(5,'e'); commit;
复制
查看 t1 表数据存储的数据文件号和块号:6号文件,15 block
select dbms_rowid.rowid_relative_fno(rowid),dbms_rowid.rowid_block_number(rowid),id from t1; DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) ID ------------------------------------ ------------------------------------ ---------- 6 15 1 6 15 2 6 15 3 6 15 4 6 15 5
复制
查看 6 号数据文件
col file_name for a50 select file_id,file_name from dba_data_files where file_id=6; FILE_ID FILE_NAME ---------- -------------------------------------------------- 6 /oracle/app/oracle/oradata/cjc/cjc_data01.dbf
复制
查看UNDO和回滚段等信息
SQL> show parameter undo_tablespace NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ undo_tablespace string UNDOTBS1 SQL> select * from v$rollname; USN NAME ---------- ------------------------------ 0 SYSTEM 1 _SYSSMU1_3724004606$ 2 _SYSSMU2_2996391332$ 3 _SYSSMU3_1723003836$ 4 _SYSSMU4_1254879796$ 5 _SYSSMU5_898567397$ 6 _SYSSMU6_1263032392$ 7 _SYSSMU7_2070203016$ 8 _SYSSMU8_517538920$ 9 _SYSSMU9_1650507775$ 10 _SYSSMU10_1197734989$ 11 rows selected
复制
更新t1表数据,不提交,值由c更新为xxxxx;
update t1 set name='xxxxx' where id=3;
复制
查看事务信息,记录在3号文件,482 block,2号rollname,18号slot
SQL> select ubafil,ubablk,xidusn,xidslot,xidsqn,start_scnb from v$transaction; UBAFIL UBABLK XIDUSN XIDSLOT XIDSQN START_SCNB ---------- ---------- ---------- ---------- ---------- ---------- 3 482 2 18 978 0
复制
字段说明:
UBAFIL: Undo block address (UBA) filenum,3号数据文件,也就是undotbs01.dbf; UBABLK: UBA block number XIDUSN: Undo segment number,也就是2号rollname(_SYSSMU2_2996391332$); XIDSLOT: Slot number XIDSQN: Sequence number START_SCNB: Start system change number (SCN) base
复制
SQL> select file_id,file_name from dba_data_files where file_id=3; FILE_ID FILE_NAME ---------- -------------------------------------------------- 3 /oracle/app/oracle/oradata/cjc/undotbs01.dbf
复制
查看对象ID
SQL> select object_id from dba_objects where object_name='T1'; OBJECT_ID ---------- 88751
复制
从上面查询信息,可以知道:
回滚块:3号文件,482 block 数据块:6文件,15 block 回滚段名称:_SYSSMU2_2996391332$ 表CJC.T1:OBJECT_ID=88751
复制
通过dump查看相关事务信息:
1.dump 回滚段头块:
---22432 select spid from v$process where addr in (select paddr from v$session where sid = (select sid from v$mystat where rownum=1)); alter system dump undo header '_SYSSMU2_2996391332$';
复制
2.dump 回滚块:
---23222 select spid from v$process where addr in (select paddr from v$session where sid = (select sid from v$mystat where rownum=1)); alter system dump datafile 3 block 482;
复制
3.dump 数据块:
---23281 select spid from v$process where addr in (select paddr from v$session where sid = (select sid from v$mystat where rownum=1)); alter system dump datafile 6 block 15;
复制
查看dump trace:
SQL> show parameter user_dump_dest NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ user_dump_dest string /oracle/app/oracle/diag/rdbms/cjc/cjc/trace
复制
一:分析回滚段头块
vi /oracle/app/oracle/diag/rdbms/cjc/cjc/trace/cjc_ora_22432.trc ******************************************************************************** Undo Segment: _SYSSMU2_2996391332$ (2) ******************************************************************************** Extent Control Header ----------------------------------------------------------------- Extent Header:: spare1: 0 spare2: 0 #extents: 6 #blocks: 47 last map 0x00000000 #maps: 0 offset: 4080 Highwater:: 0x00c001e2 ext#: 3 blk#: 2 ext size: 8
复制
其中:
_SYSSMU2_2996391332$ (2) 表示是2号段; extents: 6 表示有6个extent区(每个extent 8个block,一共48个block); blocks: 47 表示2号回滚段6个区中有47个可用undo block(去掉了一个undo segment header block); ext#: 3 表示事务发生在第3个区上(从0开始); blk#: 2 表示事务发生在2号回滚段第3个区的第2个block上; ext size: 8 表示1个区有8个undo block; 查询:可以看到,EXTENT_ID=3,对应的BLOCK_ID=480,第2个block是482,和之前v$transaction查询一致。
复制
select extent_id,file_id,block_id,blocks,bytes from dba_extents where segment_name='_SYSSMU2_2996391332$'; EXTENT_ID FILE_ID BLOCK_ID BLOCKS BYTES ---------- ---------- ---------- ---------- ---------- 0 3 144 8 65536 1 3 296 8 65536 2 3 472 8 65536 3 3 480 8 65536 4 3 464 8 65536 5 3 280 8 65536 6 rows selected.
复制
继续查看 Extent Map
Extent Map ----------------------------------------------------------------- 0x00c00091 length: 7 0x00c00128 length: 8 0x00c001d8 length: 8 0x00c001e0 length: 8 0x00c001d0 length: 8 0x00c00118 length: 8
复制
2号undo 回滚段,一共8个extent,第一个区 7个block,其他区8个block。
继续看 Retention Table
Retention Table ----------------------------------------------------------- Extent Number:0 Commit Time: 1721451627 Extent Number:1 Commit Time: 1721451627 Extent Number:2 Commit Time: 1721451627 Extent Number:3 Commit Time: 1721451627 Extent Number:4 Commit Time: 1721451627 Extent Number:5 Commit Time: 1721451627
复制
区 commit time时间:转为位时间是1970-01-21。
select to_char(to_date('1970-01-01','yyyy-mm-dd')+(1721451627/(3600*24*1000))+TO_NUMBER(SUBSTR(TZ_OFFSET(sessiontimezone), 1, 3))/24,'YYYY-MM-DD') datetime from dual; DATETIME ---------- 1970-01-21
复制
继续看 TRN CTL(事务控制)
TRN CTL:: seq: 0x0119 chd: 0x0007 ctl: 0x0001 inc: 0x00000000 nfb: 0x0000 mgc: 0xb000 xts: 0x0068 flg: 0x0001 opt: 2147483646 (0x7ffffffe) uba: 0x00c001e2.0119.37 scn: 0x0000.0012e861
复制
说明:
seq: 0x0119 表示此事务修改前的值所在的UNDO BLOCK块被覆盖了281次(16进制的0119转换为10进制是281),与下面的uba: 0x00c001e2.0119.37中的0119对应。 chd: 0x0007 表示发生一个新的事务,此时会在下面的TRNTBL::(事务表)的index=0x0007槽中放入新事务信息,即事务表的链头或叫入口。 ctl: 0x0001 表示事务表的链尾(实际上可以去TRN TBL::看index=0x0001,它对应的SCN=0x0000.0012f0d2是本事务表中最大的SCN,即此事务槽最后才会被覆盖) nfb: 0x0000 表示UNDO块在空闲池的空闲块数,0x0000表示池中有0个空闲UNDO块,即FREE BLOCKPOOL::有0个空闲的块。 flg: 0x0001 表示该块的用途,1=KTUUNDO HEADER(2=KTU UNDO BLOCK等等) uba: 0x00c001e2.0119.37 表示新事务的第一条UNDO记录(由三部分组成: undo块的地址、UNDO块被重用的次数、在UNDO块的第几条记录)
复制
继续看 FREE BLOCK POOL
FREE BLOCK POOL:: uba: 0x00000000.0119.36 ext: 0x3 spc: 0x3ae uba: 0x00000000.0119.1b ext: 0x3 spc: 0xc58 uba: 0x00000000.00e0.2a ext: 0x2d spc: 0xe46 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块中多少空闲空间,单位字节,例如16进制的3ae转换为10进制是942,从上面的UNDO空闲池中看,有空闲的UNDO块。
继续看事物表 TRN TBL
TRN TBL:: index state cflags wrap# uel scn dba parent-xid nub stmt_num cmt ------------------------------------------------------------------------------------------------ 0x00 9 0x00 0x03d3 0x0017 0x0000.0012ef89 0x00c001e2 0x0000.000.00000000 0x00000001 0x00000000 1721463352 0x01 9 0x00 0x03d3 0xffff 0x0000.0012f0d2 0x00c001e2 0x0000.000.00000000 0x00000001 0x00000000 1721463820 0x02 9 0x00 0x03d2 0x0008 0x0000.0012ed77 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721454853 0x03 9 0x00 0x03d2 0x0004 0x0000.0012e9f3 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721452827 0x04 9 0x00 0x03d2 0x0010 0x0000.0012e9fd 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721452827 0x05 9 0x00 0x03d2 0x000f 0x0000.0012ed4f 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721454853 0x06 9 0x00 0x03d3 0x0020 0x0000.0012ee99 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721463217 0x07 9 0x00 0x03d2 0x0014 0x0000.0012e86b 0x00c001e0 0x0000.000.00000000 0x00000001 0x00000000 1721451926 0x08 9 0x00 0x03d2 0x001d 0x0000.0012eda4 0x00000000 0x0000.000.00000000 0x00000000 0x00000000 1721463212 0x09 9 0x00 0x03d2 0x001b 0x0000.0012e889 0x00c001e0 0x0000.000.00000000 0x00000001 0x00000000 1721451926 0x0a 9 0x00 0x03d2 0x0003 0x0000.0012e9a1 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721452621 0x0b 9 0x00 0x03d3 0x000e 0x0000.0012efee 0x00000000 0x0000.000.00000000 0x00000000 0x00000000 1721463365 0x0c 9 0x00 0x03d2 0x0019 0x0000.0012ed2f 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721454853 0x0d 9 0x00 0x03d2 0x0005 0x0000.0012ed43 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721454853 0x0e 9 0x00 0x03d3 0x0001 0x0000.0012f05a 0x00c001e2 0x0000.000.00000000 0x00000001 0x00000000 1721463527 0x0f 9 0x00 0x03d2 0x001c 0x0000.0012ed5b 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721454853 0x10 9 0x00 0x03d2 0x0015 0x0000.0012ebb0 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721454027 0x11 9 0x00 0x03d1 0x0009 0x0000.0012e87f 0x00c001e0 0x0000.000.00000000 0x00000001 0x00000000 1721451926 0x12 10 0x80 0x03d2 0x0003 0x0000.00000000 0x00c001e2 0x0000.000.00000000 0x00000001 0x00000000 0 0x13 9 0x00 0x03d1 0x000a 0x0000.0012e8f7 0x00c001e0 0x0000.000.00000000 0x00000001 0x00000000 1721452207 0x14 9 0x00 0x03d2 0x0011 0x0000.0012e875 0x00c001e0 0x0000.000.00000000 0x00000001 0x00000000 1721451926 0x15 9 0x00 0x03d2 0x0016 0x0000.0012ec57 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721454422 0x16 9 0x00 0x03d2 0x001a 0x0000.0012ecb2 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721454594 0x17 9 0x00 0x03d2 0x000b 0x0000.0012efc1 0x00c001e2 0x0000.000.00000000 0x00000001 0x00000000 1721463364 0x18 9 0x00 0x03d2 0x001f 0x0000.0012eec4 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721463217 0x19 9 0x00 0x03d2 0x000d 0x0000.0012ed39 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721454853 0x1a 9 0x00 0x03d2 0x000c 0x0000.0012ed24 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721454853 0x1b 9 0x00 0x03d1 0x0013 0x0000.0012e8f3 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721452207 0x1c 9 0x00 0x03d2 0x0002 0x0000.0012ed68 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721454853 0x1d 9 0x00 0x03d2 0x001e 0x0000.0012edb2 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721463212 0x1e 9 0x00 0x03d2 0x0006 0x0000.0012edc8 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721463213 0x1f 9 0x00 0x03d2 0x0021 0x0000.0012ef25 0x00c001e2 0x0000.000.00000000 0x00000002 0x00000000 1721463338 0x20 9 0x00 0x03d1 0x0018 0x0000.0012eead 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721463217 0x21 9 0x00 0x03d2 0x0000 0x0000.0012ef51 0x00c001e2 0x0000.000.00000000 0x00000001 0x00000000 1721463338 EXT TRN CTL:: usn: 2 sp1:0x00000000 sp2:0x00000000 sp3:0x00000000 sp4:0x00000000 sp5:0x00000000 sp6:0x00000000 sp7:0x00000000 sp8:0x00000000
复制
TRN TBL::(事务表)是UNDO段头块最重要的部分。
字段说明:
index 表示事务表中槽号,是一个序列,从0x00开始到0x21结束,11g的版本有34个槽。 state 表示事务状态:9代表事务不活动,10代表事务正在活动,从这里我们看出16进制第index=0x12号槽上的事务正在活动。在发生事务前,Oracle会找事务控制列表中的chd=0x0007(从前面的TRN CTL得知),就是从index=0x07,存放当前最新的事务; cflags 表示正在使用事务槽的事务的状态:0x00表示非活动事务、0x80表示活动事务、0x10表示死事务、0x90表示被回滚的死事务。 wrap# 表示事务表上的事务槽被重用的次数,它是XID的一部分。0x0003 表示此时事务槽被重用了3次。 uel 表示当前活动事务所在事务槽的下一个事务槽的指针(即如果又发生一个新的事务,此时就会用到UEL指向的事务槽上的index)。 scn 表示务事启动、提交、回滚的SCN. dba 表示uba:第一部分的undo块地址,这个DBA是(rollback)回滚的起始点,是记录事务修改的最后一条记录所在UNDO块的地址。 nub 表示当前事务所用到的UNDO块的个数。 cmt 表示最接近当前的提交时间戳,是从1970年1月1号零晨开始的(以秒为单位记录)。
复制
二:分析回滚块
vi /oracle/app/oracle/diag/rdbms/cjc/cjc/trace/cjc_ora_23222.trc Start dump data blocks tsn: 2 file#:3 minblk 482 maxblk 482 Block dump from cache: Dump of buffer cache at level 4 for tsn=2 rdba=12583394 BH (0xbffed1d8) file#: 3 rdba: 0x00c001e2 (3/482) class: 20 ba: 0xbfe12000 set: 3 pool: 3 bsz: 8192 bsi: 0 sflg: 2 pwc: 335,19 dbwrid: 0 obj: -1 objn: 0 tsn: 2 afn: 3 hint: f hash: [0xd9f0d9f0,0xd9f0d9f0] lru: [0xbffed538,0xbffec2f0] ckptq: [NULL] fileq: [NULL] objq: [0xbbff0008,0xd420c608] objaq: [0xbfff1740,0xbffec328] st: XCURRENT md: NULL fpin: 'ktuwh03: ktugnb' tch: 6 flags: block_written_once redo_since_read LRBA: [0x0.0.0] LSCN: [0x0.0] HSCN: [0xffff.ffffffff] HSUB: [1] Block dump from disk: buffer tsn: 2 rdba: 0x00c001e2 (3/482) scn: 0x0000.0012f10c seq: 0x01 flg: 0x04 tail: 0xf10c0201 frmt: 0x02 chkval: 0x2dd5 type: 0x02=KTU UNDO BLOCK Hex dump of block: st=0, typ_found=1 Dump of memory from 0x00007FFFF4E4DA00 to 0x00007FFFF4E4FA00 ... ******************************************************************************** UNDO BLK: xid: 0x0002.012.000003d2 seq: 0x119 cnt: 0x37 irb: 0x37 icl: 0x0 flg: 0x0000 Rec Offset Rec Offset Rec Offset Rec Offset Rec Offset --------------------------------------------------------------------------- 0x01 0x1f94 0x02 0x1f40 0x03 0x1eec 0x04 0x1e0c 0x05 0x1da4 0x06 0x1d3c 0x07 0x1cd4 0x08 0x1c08 0x09 0x1bac 0x0a 0x1b54 0x0b 0x1afc 0x0c 0x1a2c 0x0d 0x19d0 0x0e 0x1978 0x0f 0x1920 0x10 0x1880 0x11 0x181c 0x12 0x1788 0x13 0x1720 0x14 0x16b8 0x15 0x15c8 0x16 0x1560 0x17 0x14a8 0x18 0x1440 0x19 0x13dc 0x1a 0x1378 0x1b 0x1254 0x1c 0x115c 0x1d 0x10f0 0x1e 0x1058 0x1f 0x0fec 0x20 0x0f54 0x21 0x0e94 0x22 0x0dac 0x23 0x0d50 0x24 0x0cc8 0x25 0x0c6c 0x26 0x0be4 0x27 0x0b3c 0x28 0x0ab8 0x29 0x0a50 0x2a 0x09a0 0x2b 0x0950 0x2c 0x0870 0x2d 0x07e8 0x2e 0x06f4 0x2f 0x06a4 0x30 0x0634 0x31 0x05f0 0x32 0x05ac 0x33 0x0568 0x34 0x0524 0x35 0x049c 0x36 0x042c 0x37 0x0380 ... uba: 0x00c001e2.0119.2e ctl max scn: 0x0000.0012e7bf prv tx scn: 0x0000.0012e7d2 txn start scn: scn: 0x0000.0012efeb logon user: 102 prev brb: 12583390 prev bcl: 0 *----------------------------- * Rec #0x37 slt: 0x12 objn: 88751(0x00015aaf) objd: 88751 tblspc: 9(0x00000009) * 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: 0x00c001e2.0119.35 ctl max scn: 0x0000.0012e857 prv tx scn: 0x0000.0012e861 txn start scn: scn: 0x0000.00000000 logon user: 102 prev brb: 12583392 prev bcl: 0 KDO undo record: KTB Redo op: 0x03 ver: 0x01 compat bit: 4 (post-11) padding: 1 op: Z Array Update of 1 rows: tabn: 0 slot: 2(0x2) flag: 0x2c lock: 0 ckix: 12 ncol: 2 nnew: 1 size: 0 KDO Op code: 21 row dependencies Disabled xtype: XAxtype KDO_KDOM2 flags: 0x00000080 bdba: 0x0180000f hdba: 0x0180000a itli: 2 ispac: 0 maxfr: 4858 vect = 3 col 1: [10] 63 20 20 20 20 20 20 20 20 20
复制
其中:col 1: [10] 63 20 20 20 20 20 20 20 20 20 表示第3行第2列(name)修改前的值:
可以通过utl_raw.cast_to_varchar2转换:
SQL> SELECT utl_raw.cast_to_varchar2(replace('63 20 20 20 20 20 20 20 20 20',' ')) value FROM dual; VALUE -------------------------------------------------------------------------------- c
复制
记录修改之前的列值 NAME=‘C’;
三:分析数据块
vi /oracle/app/oracle/diag/rdbms/cjc/cjc/trace/cjc_ora_23281.trc Start dump data blocks tsn: 9 file#:6 minblk 15 maxblk 15 Block dump from cache: Dump of buffer cache at level 4 for tsn=9 rdba=25165839 BH (0xbdf91198) file#: 6 rdba: 0x0180000f (6/15) class: 1 ba: 0xbd4a2000 set: 3 pool: 3 bsz: 8192 bsi: 0 sflg: 2 pwc: 335,19 dbwrid: 0 obj: 88751 objn: 88751 tsn: 9 afn: 6 hint: f hash: [0xbdff3a28,0xd9833a70] lru: [0xbdf913c0,0xbdf91150] ckptq: [NULL] fileq: [NULL] objq: [0xbdff3bc0,0xd4254bb0] objaq: [0xbdff3bd0,0xd4254ba0] st: XCURRENT md: NULL fpin: 'ktspbwh2: ktspfmdb' tch: 1 flags: block_written_once redo_since_read LRBA: [0x0.0.0] LSCN: [0x0.0] HSCN: [0xffff.ffffffff] HSUB: [1] BH (0xbdff3970) file#: 6 rdba: 0x0180000f (6/15) class: 1 ba: 0xbdebc000 set: 3 pool: 3 bsz: 8192 bsi: 0 sflg: 2 pwc: 335,19 dbwrid: 0 obj: 88751 objn: 88751 tsn: 9 afn: 6 hint: f hash: [0xd9833a70,0xbdf91250] lru: [0xd8103938,0xbffe6788] lru-flags: moved_to_tail ckptq: [NULL] fileq: [NULL] objq: [NULL] objaq: [NULL] st: CR md: NULL fpin: 'ktspbwh2: ktspfmdb' tch: 1 cr: [scn: 0x0.12f104],[xid: 0x0.0.0],[uba: 0x0.0.0],[cls: 0x0.12f104],[sfl: 0x0],[lc: 0x0.12f05a] flags: block_written_once redo_since_read Block dump from disk: buffer tsn: 9 rdba: 0x0180000f (6/15) scn: 0x0000.0012f10c seq: 0x01 flg: 0x04 tail: 0xf10c0601 frmt: 0x02 chkval: 0x4093 type: 0x06=trans data Hex dump of block: st=0, typ_found=1 Dump of memory from 0x00007FFFF4E4DA00 to 0x00007FFFF4E4FA00 Dump of memory from 0x00007FFFF4E4DA00 to 0x00007FFFF4E4FA00 ..... Repeat 497 times 7FFFF4E4F9A0 00000000 2C000000 C1020200 20650A06 [.......,......e ] 7FFFF4E4F9B0 20202020 20202020 0202002C 640A05C1 [ ,......d] 7FFFF4E4F9C0 20202020 20202020 02022C20 0A04C102 [ ,......] 7FFFF4E4F9D0 78787878 20202078 002C2020 03C10202 [xxxxx ,.....] 7FFFF4E4F9E0 2020620A 20202020 2C202020 C1020200 [.b ,....] 7FFFF4E4F9F0 20610A02 20202020 20202020 F10C0601 [..a ....] Block header dump: 0x0180000f
复制
可以看到name列值:a,b,xxxxx,d,e;
数据块内的事务槽信息:
Block header dump: 0x0180000f Object id on Block? Y seg/obj: 0x15aaf csc: 0x00.12f105 itc: 2 flg: E typ: 1 - DATA brn: 0 bdba: 0x1800008 ver: 0x01 opc: 0 inc: 0 exflg: 0 Itl Xid Uba Flag Lck Scn/Fsc 0x01 0x0002.00e.000003d3 0x00c001e2.0119.34 C--- 0 scn 0x0000.0012f05a 0x02 0x0002.012.000003d2 0x00c001e2.0119.37 ---- 1 fsc 0x0000.00000000 bdba: 0x0180000f data_block_dump,data header at 0x7ffff4e4da64
复制
Object id on Block? Y 该块是否属于某个对象 seg/obj: 0x15aaf 0x15aaf 16进制转10进制是88751,也就是t1表的object_id。 itc: 2 数据块内事物槽slot的数量 typ: 1 - DATA 类型1表示数据,类型2表示索引 bdba --Block relative data block address(RDBA) Xid:事务ID usn#.slot#.warp# Undo Segment Number +Transaction Table Slot Number+ Wrap 回滚段号.事务槽号.被重用次数 xid 可以唯一标识一个事务,为什么要记录重用次数? 已提交的事务对应事务槽可以重用,只有回滚段号+事务槽号+重用次数,才能唯一标识一个事务,就像去某餐厅就餐,通过座位号取餐一样,客人离开后座位会被重用给其他客人,但可以通过 餐厅、座位号、座位重用次数唯一标识用餐的客人。 Xid=0x0002.012.000003d2 表示: 2号回滚段,18号事务槽(012的16进制转换为10进制是18),重用了978次(3d2的16进制转换为10进制是978)。 Uba:回滚段地址 该事务对应的回滚段地址 第1段地址:回滚数据块的地址,包括UNDO文件号和数据块号 第2段地址:回滚序列号 第3段地址:回滚记录号 其中:0x00c001e2.0119.37 表示 3号文件(fild_id=3 undotbs01.dbf),482号block(1e2转10进制是482),回滚序列号281,回滚记录号55。 回滚块地址(undo文件号和数据块号)+回滚序列号+回滚记录号 SQL> select ubafil,ubablk,xidusn,xidslot,xidsqn,start_scnb from v$transaction; UBAFIL UBABLK XIDUSN XIDSLOT XIDSQN START_SCNB ---------- ---------- ---------- ---------- ---------- ---------- 3 482 2 18 978 0 Flag:事务标志位。这个标志位就记录了这个事务的操作,各个标志的含义分别是: ----- = 事务是活动的,或者已提交但没有执行块清除。 C--- = 事务已经提交并且清除了行锁。 -B-- = this undo record contains the undo for this ITL entry --U- = 事务已经提交(SCN已经是最大值),但是锁定还没有清除(快速清除)。 ---T =当块清除的SCN被记录时,该事务仍然是活动的,块上如果有已经提交的事务,那么在clean ount的时候,块会被进行清除,但是这个块里面的事务不会被清除。 Lck:影响的记录数 Scn/Fsc:快速提交(Fast Commit Fsc)的SCN或者Commit SCN
复制
...... block_row_dump: tab 0, row 0, @0x1f87 tl: 17 fb: --H-FL-- lb: 0x0 cc: 2 col 0: [ 2] c1 02 col 1: [10] 61 20 20 20 20 20 20 20 20 20 tab 0, row 1, @0x1f76 tl: 17 fb: --H-FL-- lb: 0x0 cc: 2 col 0: [ 2] c1 03 col 1: [10] 62 20 20 20 20 20 20 20 20 20 tab 0, row 2, @0x1f65 tl: 17 fb: --H-FL-- lb: 0x2 cc: 2 col 0: [ 2] c1 04 col 1: [10] 78 78 78 78 78 20 20 20 20 20 tab 0, row 3, @0x1f54 tl: 17 fb: --H-FL-- lb: 0x0 cc: 2 col 0: [ 2] c1 05 col 1: [10] 64 20 20 20 20 20 20 20 20 20 tab 0, row 4, @0x1f43 tl: 17 fb: --H-FL-- lb: 0x0 cc: 2 col 0: [ 2] c1 06 col 1: [10] 65 20 20 20 20 20 20 20 20 20 end_of_block_dump
复制
其中
tab 0, row 2, @0x1f65
tl: 17 fb: --H-FL-- lb: 0x2 cc: 2
(1) lb: 0x2说明事物在该数据行上的锁还没清除,并且该锁指向02号事物槽。
(2) lb: 和上面的 ITL 的 lck 相对应表示这行是否被lock 了;
(3) cc: 有几列数据 这里只能表示255列 超过了就会有链接行;
可以看到对于的NAME列值,即使事物没有提交,数据块里的第3行NAME值从之前的c变成了xxxxx。
COL 第1行 FOR A5 COL 第2行 FOR A5 COL 第3行 FOR A5 COL 第4行 FOR A5 COL 第5行 FOR A5 SELECT utl_raw.cast_to_varchar2(replace('61 20 20 20 20 20 20 20 20 20',' ')) AS "第1行", utl_raw.cast_to_varchar2(replace('62 20 20 20 20 20 20 20 20 20',' ')) AS "第2行", utl_raw.cast_to_varchar2(replace('78 78 78 78 78 20 20 20 20 20',' ')) AS "第3行", utl_raw.cast_to_varchar2(replace('64 20 20 20 20 20 20 20 20 20',' ')) AS "第4行", utl_raw.cast_to_varchar2(replace('65 20 20 20 20 20 20 20 20 20',' ')) AS "第5行" FROM dual; 第1行 第2行 第3行 第4行 第5行 ----- ----- ----- ----- ----- a b xxxxx d e
复制
和修改数据的会话,看到的数据一致:
SQL> select name from t1; NAME ---------- a b xxxxx d e
复制
总结:
执行update cjc.t1 set name=‘xxxxx’ where id=3;后,发生了什么?
1.UNDO段头块更新事物表
事物开始,在UNDO表空间中找到一个相对空闲的UNDO段,在UNDO段头块事物表里找到一行(slot),记录自己的事物信息(xid);
事物表如下,记录了为该事物分配的rollname是_SYSSMU2_2996391332$,dba=0x00c001e2记录了undo block 482,state=9说明是活动的事物。
******************************************************************************** Undo Segment: _SYSSMU2_2996391332$ (2) ******************************************************************************** ...... TRN TBL:: index state cflags wrap# uel scn dba parent-xid nub stmt_num cmt ------------------------------------------------------------------------------------------------ 0x00 9 0x00 0x03d3 0x0017 0x0000.0012ef89 0x00c001e2 0x0000.000.00000000 0x00000001 0x00000000 1721463352 ...... 0x11 9 0x00 0x03d1 0x0009 0x0000.0012e87f 0x00c001e0 0x0000.000.00000000 0x00000001 0x00000000 1721451926 0x12 10 0x80 0x03d2 0x0003 0x0000.00000000 0x00c001e2 0x0000.000.00000000 0x00000001 0x00000000 0 0x13 9 0x00 0x03d1 0x000a 0x0000.0012e8f7 0x00c001e0 0x0000.000.00000000 0x00000001 0x00000000 1721452207 0x14 9 0x00 0x03d2 0x0011 0x0000.0012e875 0x00c001e0 0x0000.000.00000000 0x00000001 0x00000000 1721451926 0x15 9 0x00 0x03d2 0x0016 0x0000.0012ec57 0x00c001e1 0x0000.000.00000000 0x00000001 0x00000000 1721454422
复制
2.回滚段中为事务分配UNDO块
将分配的UNDO块地址写入到事务表里,就是第1步的dba地址(dba=0x00c001e2记录了undo block 482);
3.修改数据块事物槽
数据块头部事务槽里,写入xid(指向事务表),uba地址(指定回滚块) 。数据块内的事务槽信息:
Block header dump: 0x0180000f Object id on Block? Y seg/obj: 0x15aaf csc: 0x00.12f105 itc: 2 flg: E typ: 1 - DATA brn: 0 bdba: 0x1800008 ver: 0x01 opc: 0 inc: 0 exflg: 0 Itl Xid Uba Flag Lck Scn/Fsc 0x01 0x0002.00e.000003d3 0x00c001e2.0119.34 C--- 0 scn 0x0000.0012f05a 0x02 0x0002.012.000003d2 0x00c001e2.0119.37 ---- 1 fsc 0x0000.00000000 bdba: 0x0180000f data_block_dump,data header at 0x7ffff4e4da64
复制
其中:Xid=0x0002.012.000003d2 表示:
2号回滚段,18号事务槽(012的16进制转换为10进制是18)(也就是undo段头块里事物表的第19行[0-18]),重用了978次(3d2的16进制转换为10进制是978)。
其中:Uba=0x00c001e2.0119.37 表示
3号文件(fild_id=3 undotbs01.dbf),482号block(1e2转10进制是482),回滚序列号281,回滚记录号55。
数据库头部事物槽信息记录了该事物对应undo段头块事物表位置,对应undo块号、位置等信息。
4.undo块记录前镜像
修改前的数据写入到UNDO块,地址指向undo块
itli: 2 ispac: 0 maxfr: 4858 vect = 3 col 1: [10] 63 20 20 20 20 20 20 20 20 20
复制
可以看到修改第3行第二列的前镜像值是:63 20 20 20 20 20 20 20 20 20
转换回原值,是NAME=‘c’
SQL> SELECT utl_raw.cast_to_varchar2(replace('63 20 20 20 20 20 20 20 20 20',' ')) value FROM dual; VALUE -------------------------------------------------------------------------------- c
复制
5.修改数据块
tl: 17 fb: --H-FL-- lb: 0x2 cc: 2 col 0: [ 2] c1 04 col 1: [10] 78 78 78 78 78 20 20 20 20 20
复制
转换修改后的值,是NAME=‘c’
SQL> SELECT utl_raw.cast_to_varchar2(replace('78 78 78 78 78 20 20 20 20 20',' ')) value FROM dual; VALUE -------------------------------------------------------------------------------- xxxxx
复制
可以看到,一个事物最少要修改3种类型块:
1:回滚段头块,更新事物表;
2.数据块,更新头部事物槽、行标志(记录具体slot),更新具体数据;
3.回滚块,数据修改前的值;
并且每次数据块的修改前,都会记录redo log数据。
思考1:事物回滚是怎么实现的?
同一个事物可能对应多个undo块,后一个undo块存有指向前一个undo块的指针,undo块之间组成了一个单向链表,事物槽里记录的是最新undo块的地址。
事物回滚时,通过事物表里找到最新的undo块,根据undo块的数据更新对应数据块的数据进行回滚,然后通过指针找到上一个undo块地址,然后回滚undo块内容,最终依次回滚这个事物对应的所有回滚块,从而完成事物的回滚。
思考2:行锁是怎么实现的?
Oracle的锁机制是一种轻量级的锁定机制,不是通过构建锁列表来进行数据的锁定管理,而是直接将锁作为数据块的属性,存储在数据块首部。
通过ITL来实现的,一个事务要修改块中的数据,必须获得该块中的一个itl。
通过itl和undo segment header中的transaction table,可以知道事务处于活动阶段,还是已经完成。
事务在修改块时(其实就是在修改行)会检查行中row header中的标志位,如果该标志位为0(该行没有被活动的事务锁住,这是可能要进行deferred block cleanout等工作),就把该标志位修改为事务在该块获得的itl的序号,这样当前事务就获得了对记录的锁定,然后就可以修改行数据了,这也就是oracle行锁实现的原理。
如果行未被锁定,会为该事务分配一个ITL slot,并将该ITL的序号写入到row header的lock byte中,从而实现对行的锁定。
此时,其他事务如果试图修改同一行数据,会发现lock byte不为0,从而进入等待状态,直到当前事务提交或回滚并释放锁。
思考3:事物提交后,数据块的事物槽、行锁等信息是立即清除吗?
transaction 提交后, redo完成记录,同时还清除回滚段的事务信息,包括行级锁、ITL 信息 (commit 标志,SCN等) 等。
清除这些事务段的信息的过程就叫做块清除,在完成块清除时, 我们本事务修改的数据块就会存在两种可能:
(1)所有的数据块还保存在buffer cache中;
(2)部分数据块或者是全部数据块由于 LRU 管理 已经被刷出了 buffer cache,存在磁盘上。
oracle 为了考虑到块清除的成本以及性能,会作以下两种方式的块清除处理:
(1)快速块清除 (fast block cleanout )
当事务修改的数据块全部保存在 buffer cache 并且修改数据块的数据量没有超过buffer cache的 10% ,快速清除事务信息。
(2)延迟块清除 (delayed block cleanout)
当修改的数据块的阀值超过10% 或者本次事务相关的数据块已经被刷出了buffer cache, oracle 会下次访问此 block 时再清除事务信息。
这也是为什么有时select语句也会参数少量的redo数据的原因。
思考4:undo段头块和undo普通块损坏数据库会影响数据库启动吗?
undo段头坏损坏可能会自动停库,并且数据库无法open,undo普通块损坏通常不会自动停库,不会影响open,详细内容可以参考我的另一篇文章。
《Oracle 数据库通过BBED模拟UNDO坏块》
本文参考:
相老师的课程: 1.图解深入剖析一个事物的操作流程 2.深入剖析事物槽及Oracle多种提交方式 Oracle数据库UNDO段头块格式深度解析: https://blog.csdn.net/qq_28721869/article/details/118440656 oracle 块延迟清除(delayed block cleanout) https://blog.csdn.net/sstevencao/article/details/84124598
复制
###chenjuchao 20240721###
欢迎关注我的公众号《IT小Chen》
评论





