事务的修改过程

块和表不是一一对应的,一个表很大肯定对应多个块,但如果表很小可以多表放一个块。Oracle读数据去内存是读一个块不是一个记录。

《 expert oracle database architecture 9i and 10g programming techniques and solutions》中所述
The table directory, if present, contains information about the tables that store rows in this block(data from more than one table may be stored on the same block).
 

下面描述下事务的修改过程

1、第一步

一个事务开始,首先在undo表空间里面找相对空闲的undo段的段头块的事务表里的一行,将自己的xid写上,同时在undo段里面分配一个空块作为回滚块,同时将回滚块的地址写到事务表的事务槽里。

2、第二步

要修改具体的数据了

修改任何一个数据库都是要在数据块块的头部获取一个事务槽,然后写上xid,获取到事务槽就开始修改数据块,修改数据的时候,还将修改前的数据写到回滚里,因为这个事务已经分配一个回滚块了,就直接写到回滚块里面去,同时将这个数据块所对应的回滚块的地址也写到数据块的事务槽里,回滚数据写完了,接下来修改实实在在的行,第一个数据块(应该是行吧)修改完了,再修改第二个数据块(行?),同样的操作继续修改数据块(行?),同时如果这个时候一个回滚块不够,要分配第二第三个回滚块(一个数据块对应多个rollback块,不是改一次对应一次块,而是改一次在rollback中加行),同是一个事务的回滚块之间要串起来,由新到旧的指向,同时如果加了回滚块,会把最新的回滚块信息uba地址写到该事务的事务表里(之前的被覆盖了,串联起来找?)。

以上是整个事务的操作流程,这三个回滚块串起来以及事务表的uba指向最新的回滚块,这样为了更方便的回滚。在每个数据块里面,直接写uba指向自己的undo数据块,为了更方便的构造cr块及一致性读。同时,一个事务信息在两个位置都有,数据块的事务槽(ITL)里有,undo段头块(undo segment header)的事务表里有,数据块的事务槽指向事务表,这个和Oracle的一种提交方式有关!

一个事务开始以后,Oracle修改了四个地方:(上图 每次还要写REDO呢)

回滚段的段头块的事务表被修改;

回滚块被修改;

数据块的事务槽被修改;

数据块的数据行被修改。

这四个地方的数据都在数据块里面,数据块的任务地方的改变都会产生redo,redo不仅仅记录的是数据行的改变,事务槽的改变、undo块的改变、事务表的改变一样都会产生redo,这就是一个事务的操作流程。

本帖最后由 mlx_861201 于 2013-3-23 10:45 编辑
 
Commit过程中redo、undo、数据块交互过程实验
实验目的
Commit过程中redo、undo、数据块交互过程 。如下图:
   

undo数据块、undo段头块、数据块之间的关系

实验准备
1、  创建cricket用户。
create user cricket identified by cricket;
grant dba to cricket;
2、  创建score表。
create table score(
       TEAM varchar2(30),
       runs number,
       WICKETS number
)
3、  构成数据
Insert into score values(‘ENG’,841,3);
Insert into score values(‘AUS’,77,8);
Commit;
实验过程1、执行第一句UPDATE
Update score set runs=77 where team =’AUS’;
A、undo段头块变化情况。
         通过select * from v$transaction;查询活动的事务,获得事务所在undo段,以及undo块地址。本例事务所在undo段为10号段,事务槽为15号事务槽,事务槽seq为4690,undo块为3 号文件第       2950块。
         Dump出undo段段头块。altersystem dump undo header ' _SYSSMU10_4131489474$';
         

 
         可以看到undo段头块事务表的第15号事务槽的state 是10,cflags是0x80,wrap是0x1213,dba为undo块地址 ,转换为文件号和块号为3+2950,内容与v$transaction反映的一致。
B、undo块变化情况。
        通过v$transaction可以看到该事务对应的undo块为3号文件的2950块。
        Dump出该undo块: alter system dump datafile 3 block 2950。
        查看undo块概况信息:
       

       Xid:事务号,xid由 undosegment no + slot no + seq no组成。
         Seq:该undo块的序列号,表示该undo块被覆盖的次数。该值就是v$transaction视图中的ubaseq。
         Cnt:该undo块中undo记录数。该值就是v$transaction试图中的UBAREC。
         irb:表示当前事务的前进项存放的记录号,该例中可以直接到底0X2e记录上查找。 Rec:undo记录号。
         Offset:偏移量。第一个offset的偏移量是4080 。
         查看第0X2e个undo 记录信息:
          

         Rec #0x2e:该undo记录的号码。
         Slt:事务表槽号。
         Objn:对应数据块对象号。
         Tblspc:对应数据块表空间号。
         Col:保存前进项值。Ox4c-1=77。
         Bdab:数据块地址。
         Hdba:数据块所在段的段头块。
C、数据块头变化
         通过 rowid 可以知道数据块存放在4号文件550号块。
         Dump该数据块,查看块头事务槽。altersystem dump datafile 4 block 550。
          

        1号事务槽的Xid与undo块保存的Xid一致。Uba指向undo块,028b表示块的覆盖次数,2e表示undo记录号。Flag为----表示事务未提交。Lck为1表示有一行被锁定。
D、数据行变化
         查看数据块中的行信息
       

 
         lb:0x1表示该行数据被1号事务槽锁定。第二列数据已经被修改Ox4c-1=75。
E、redo变化
         1、查找正在使用的logfile
             SELECT * FROM v$LOGFILEWHERE GROUP# =(Select GROUP# from v$log where status = ‘CURRENT’);
         2、dump正在使用的日志文件( /u01/app/oracle/oradata/orcl/redo04.log);
                    alter   system   dump   logfile   'redoFile' ;
           找到与当前修改对象相关的内容(对象号76014)。
          包含三个改变向量(CHANGE),
          Change1是对数据块修改的redo信息。
          

          DBA:数据块地址。
          OBJ:数据块所在对象号。
          OP:11.19。表示update row array
          Col 1:[ 2] c1 4c  保存修改后的数据。
          Chage2是对undo段头块修改参数的redo信息。
          

          DBA:undo段头块地址。
          OBJ:修改块所在对象号。
          OP:5.2表示对undo段头块的修改。
          UBA:undo块地址。
         Change3是对undo数据块的修改。
          
         DBA:undo块地址。
         XID:事务号。
         BDBA:数据块地址。
         HDBA:数据块段头块地址。
         UBA:undo块地址。
2、执行commit;A、undo段头块变化情况。
         Dump出undo段段头块。alter system dump undo header ' _SYSSMU4_1003442803$';
         Commit后段头事务表如下:
          
         Commit前段头事务表如下:
         
         变化:事务槽15的state变成了9,cflags变为00,uel变成了无限大(ffff),scn变成了提交是的scn。
B、undo块变化情况。
         Dump出undo块。Dump出该undo块: alter systemdump datafile 3 block 2950。
         
         Undo块头信息没有发生变化,直接查看0x2e号undo条目,可以发现没有任何变化。
      
         
C、数据块事务槽变化情况。
         通过 rowid 可以知道数据块存放在4号文件550号块。
         先刷新内存alter systemflush buffer_cache。
         Dump该数据块,查看块头事务槽。altersystem dump datafile 4 block 550。
          
         可以看到没有变化,commit之后flag还是“--U-”, lck还是“1”,fscchans。这就是快速提交。
D、数据行变化情况。
         查看数据块中的行信息:
          
         lb:0x1表示该行数据被1号事务槽锁定。第二列数据已经被修改Ox4c-1=75。
E、redo变化情况。
         Dump出当前redo日志文件: alter   system   dump   logfile   'redoFile' ;
          可以看到多了两条重做记录,
         1、数据提交的重做记录,里面只有一个change:
          
         增加的这条change为对undo段头事务表的修改产生的redo信息。OP:5.4
         2、一个为写文件的重做记录
          
         产生了一天写入redo条目。OP:23.1








 

1.jpg (161.05 KB, 下载次数: 9)

2.jpg (61.07 KB, 下载次数: 8)

3.jpg (69.15 KB, 下载次数: 14)

6.jpg (34.07 KB, 下载次数: 15)

SYS用户可查询 buffer header数据,可以从数据库的数据字典表中查询得到,这张字典表就是x$bh,其中的bh就是指buffer headers,每个buffer在x$bh中都存在一条记录. buffer header中存储每个buffer容纳的数据块的文件号,块地址,状态等重要信息,根据这些信息,结合dba_extents视图,可以很容易地找到每个buffer对应的对象信息: x$bh中还有一个重要的字段TCH,TCH为Touch的缩写,表示一个Buffer的访问次数,buffer被访问的次数越多,说明该buffer就越抢手,也就可能存在热块竞争的问题 可以结合DUMP BH来对比X$BH中字段。

SQL> desc v$bh;

 Name             Type
 -----------------------------
 ADDR             RAW(4)    --Hex address of the Buffer Header.视图中某行的地址-缓冲区头的十六进制地址
 INDX             NUMBER    --Buffer Header number
 INST_ID          NUMBER
 HLADDR           RAW(4)    --即hash chain latch address可以和v$latch_children.addr关联,把latch和数据块关联起来
 BLSIZ            NUMBER    --块大小
 NXT_HASH         RAW(4)  --下一个BH的HASH值
 PRV_HASH         RAW(4)  --前一个BH的HASH值
 NXT_REPL         RAW(4)  --下一个BH的在LRU链上HASH值
 PRV_REPL         RAW(4)  --前一个BH的在LRU链上HASH值
 FLAG             NUMBER      ---块的状态,在BH中可能是buffer_dirty block_written_once redo_since_read,详见最后
 FLAG2            NUMBER
 LOBID            NUMBER
 RFLAG            NUMBER    
 SFLAG            NUMBER
 LRU_FLAG         NUMBER   --- LRU_FLAG,详见最后
 TS#              NUMBER    --tablespace number表空间号
 FILE#            NUMBER    --块在数据库内绝对文件号
 DBARFIL          NUMBER    --块的相对文件号
 DBABLK           NUMBER    --块号--在数据文件上的
 CLASS            NUMBER    --太长,见最下面。
 STATE            NUMBER    --太长,见最下面。
 MODE_HELD        NUMBER    --
 CHANGES          NUMBER
 CSTATE           NUMBER
 LE_ADDR          RAW(4)    --Lock Element address (OPS)
 DIRTY_QUEUE      NUMBER    --LRUW上的buffer
 SET_DS           RAW(4)    -- Buffer cache set this buffer is under
 OBJ              NUMBER    --对象号
 BA               RAW(4)    --BUFFER ADDRESS--在内存中的地址
 CR_SCN_BAS       NUMBER    --Consistent Read SCN base 一致读SCN低位
 CR_SCN_WRP       NUMBER    --Consistent Read SCN wrap  一致读SCN高位
 CR_XID_USN       NUMBER    -- CR XID Undo segment no
 CR_XID_SLT       NUMBER    -- CR XID slot
 CR_XID_SQN       NUMBER    --CR XID Sequence
 CR_UBA_FIL       NUMBER    -- CR UBA file
 CR_UBA_BLK       NUMBER    -- CR UBA Block
 CR_UBA_SEQ       NUMBER    --CR UBA sequence
 CR_UBA_REC       NUMBER    --CR UBA record
 CR_SFL           NUMBER    --
 CR_CLS_BAS       NUMBER
 CR_CLS_WRP       NUMBER
 LRBA_SEQ         NUMBER    --Lowest RBA needed to recover block in cache
 LRBA_BNO         NUMBER
 HSCN_BAS         NUMBER    ---SCN的低位
 HSCN_WRP         NUMBER    ---SCN的高位
 HSUB_SCN         NUMBER
 US_NXT           RAW(4)
 US_PRV           RAW(4)
 WA_NXT           RAW(4)
 WA_PRV           RAW(4)
 OQ_NXT           RAW(4)    --- 对象队列前一个HASH值
 OQ_PRV           RAW(4)    --- 对象队列后一个HASH值
 AQ_NXT           RAW(4)    ---辅助对象队列前一个HASH值
 AQ_PRV           RAW(4)    ---辅助对象队列后一个HASH值
 OBJ_FLAG         NUMBER
 TCH              NUMBER    --Touch的缩写,表示一个Buffer的访问次数
 TIM              NUMBER    --Touch Time
 CR_RFCNT         NUMBER

 SHR_RFCNT        NUMBER

bh即描述了数据块块头的信息,buffer header描述了数据块的信息.

 

 chain都是这样的。

下面查询可获得数据库最繁忙的Buffer

select * from (select addr,ts#,file#,dbarfil,dbablk,tch from x$bh order by tch desc) where rownum<11;

在结合dba_extents中的信息,可以查询得到这些热点Buffer都来自哪些对象:

select e.owner,e.segment_name,e.segment_type from dba_extents e,(select * from(select addr,ts#,file#,dbarfil,dbablk,tch from x$bh order by tch desc)

where rownum<11)b

where e.relative_fno=b.dbarfil

and e.block_id<=b.dbablk

and e.block_id+e.blocks>b.dbablk;

热点块与竞争的解决可以从v$latch_children中查询具体的子Latch信息

select * from(select addr,child#,gets,misses,sleeps,immediate_gets igets,immediate_misses imiss,spin_gets sgets

from v$latch_children

where name='cache buffers chains'

order by sleeps desc)

where rownum<11;

X$BH中还存在另外一个关键字段HLADDR,即Hash Chain Latch Address,这个字段可以和v$latch_child.addr进行连接,这样就可以把具体的Latch竞争和数据块关联起来,在结合dba_extents视图,就可以找到具体的热点竞争对象,找到具体热点竞争对象之后,可以结合v$sqlarea或者v$sqltext,找到频繁操作这些对象的SQL,然后对其进行优化,即可缓解或解决热点块竞争的问题。

可以通过如下查询获取当前持有最热点数据块的Latch及Buffer信息:

select b.addr,a.ts#,a.dbarfil,a.tch,b.gets,b.misses,b.sleeps from

(select * from (

select addr,ts#,file#,dbarfil,dbablk,tch,hladdr from x$bh order by

tch desc) where rownum<11) a,

(select addr,gets,misses,sleeps from v$latch_children where

name='cache buffers chains')b

where a.hladdr=b.addr

根据如下的sql找到这些热点buffer的对象的信息

select e.owner,e.segment_name,e.segment_type from dba_extents e,

(select * from (select addr,ts#,file#,dbarfil,dbablk,tch from x$bh

order by tch desc)

where rownum<11) b

where e.relative_fno=b.dbarfil and e.block_id<=b.dbablk

and e.block_id+e.blocks>b.dbablk;

结合v$sqltext或v$sqlarea,可以找到操作这些对象的相关SQL,继续查询:

找到sql之后,就可以通过优化SQL减少数据的访问。

break on hash_value skip 1;

select hash_value,sql_text from v$sqltext

where (hash_value,address) in (

select a.hash_value,a.address from v$sqltext a,

(select distinct a.owner,a.segment_name,a.segment_type

from dba_extents a,

(select dbarfil,dbablk from (

select dbarfil,dbablk from x$bh order by tch desc)

where rownum<11) b

where a.relative_fno=b.dbarfil

and a.block_id<=b.dbablk

and a.block_id+a.blocks>b.dbablk) b

where a.sql_text like '%'||b.segment_name||'%' and b.segment_type='TABLE'

)order by hash_value,address,piece;

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值