首页 小组 问答 话题 好文 素材 用户 唠叨 我的社区

[Mysql]扒开Oracle数据块,探讨事物槽、UNDO等工作机制!

天启Lv.1普通用户
2024-08-21 18:29:42
0
161

说明:
本文通过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_TAB*** 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_372***4606$
     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: 0x01***00f  hdba: 0x01***00a
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: 0x01***00f (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: 0x01***00f (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: 0x01***00f (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:  0x01***00f

可以看到name列值:a,b,xxxxx,d,e;
数据块内的事务槽信息:

Block header dump:  0x01***00f
 Object id on Block? Y
 seg/obj: 0x15aaf  csc: 0x00.12f105  itc: 2  flg: E  typ: 1 - DATA
     brn: 0  bdba: 0x1***008 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: 0x01***00f
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:  0x01***00f
 Object id on Block? Y
 seg/obj: 0x15aaf  csc: 0x00.12f105  itc: 2  flg: E  typ: 1 - DATA
     brn: 0  bdba: 0x1***008 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: 0x01***00f
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/ssteven***/article/details/84124598
天启
天启

62 天前

签名 : 大运河向南是我家   161       0
评论
站长交流