一. 相关说明

            Oracle的数据放在表里面,表的数据表段(segment)里,segment 由extents 组成,extents 由Blocks组成。 每个block 可以存放多个row。

            OracleSGA里由一个DB buffer 的cache,该区域由default,keep 和 recycle pool组成。 默认情况下,block 会加载到defaultpool里,Oracle 对数据块的所有操作都在这个pool里进行,包括对数据的修改,修改之后,会有dbwr进行进行写磁盘。 这个是一个比较复杂的过程,具体参考我的Blog:

            Oracle Buffer Cache 原理

           ​​ http://www.cndba.cn/Dave/article/1398​

 

 

二. 相关测试

2.1 创建一个死循环的存储过程

 

CREATE OR REPLACE PROCEDURE SYS.proc_test

AS

str varchar2(100);

i number;

BEGIN

i:=1;

   while(true) loop

     selectobject_name into str from t1 where object_name='RB_TEST';

     if mod(i,1000) =0 then

     DBMS_OUTPUT.put_line(i);

     end if;

     i :=i+1;

end loop;

END ;

/

--这个过程的作用就是循环的去访问一个block

 

2.2 查看这个block的file_id 和 block_id

 

/* Formatted on 2011/7/4 19:45:56(QP5 v5.163.1008.3004) */

SELECT DBMS_ROWID.rowid_relative_fno(ROWID)REL_FNO,

       DBMS_ROWID.rowid_block_number(ROWID)BLOCKNO,

       DBMS_ROWID.rowid_row_number(ROWID) ROWNO

  FROM t1

 WHERE object_name = 'RB_TEST';

 

SYS@anqing2(rac2)> SELECTDBMS_ROWID.rowid_relative_fno (ROWID) REL_FNO,

 2        DBMS_ROWID.rowid_block_number (ROWID) BLOCKNO,

 3        DBMS_ROWID.rowid_row_number (ROWID) ROWNO

 4    FROM t1

 5   WHERE object_name = 'RB_TEST';

 

REL_FNO   BLOCKNO      ROWNO

---------- ---------- ----------

1     294838         54

 

2.3 开启2个session,去调用这个过程,实现不断访问一个block

SYS@anqing2(rac2)> select sid from v$sesstat where rownum=1;

      SID

----------

      147

SYS@anqing1(rac1)> select sid fromv$sesstat where rownum=1;

 

      SID

----------

      141

SYS@anqing2(rac2)> exec proc_test

--持续进行,因为是个死循环---

SYS@anqing1(rac1)> exec proc_test

--持续进行,因为是个死循环---

 

 

2.4  查看等待事件

SYS@anqing1(rac1)> select event fromgv$session_wait where sid=147 and inst_id=2;

 

EVENT

----------------------------------------------------------------

latch: cache bufferschains

 

SYS@anqing1(rac1)> select event fromgv$session_wait where sid=141 and inst_id=1;

 

EVENT

----------------------------------------------------------------

latch: cache bufferschains

 

 

2.5  说明

            本来测试数据块的串行访问的,不过通过以上测试到模拟了另一种情况: 热块导致的latch: cache buffers chains.

 

在我的blog里对这个latch 等待有说明:

            锁 死锁 阻塞 Latch 等待 详解

        

 

            访问频率非常高的数据块被称为热快(Hot Block),当很多用户一起去访问某几个数据块时,就会导致一些Latch争用,最常见的latch争用有:

            (1)buffer busy waits

            (2)cache buffer chain

这两个Latch的争用分别发生在访问数据块的不同时刻。

           

            当一个会话需要去访问一个内存块时,它首先要去一个像链表一样的结构中去搜索这个数据块是否在内存中,当会话访问这个链表的时候需要获得一个Latch,如果获取失败,将会产生Latch cache buffer chain 等待,导致这个等待的原因是访问相同的数据块的会话太多或者这个列表太长(如果读到内存中的数据太多,需要管理数据块的hash列表就会很长,这样会话扫描列表的时间就会增加,持有chache buffer chain latch的时间就会变长,其他会话获得这个Latch的机会就会降低,等待就会增加)。

            当一个会话需要访问一个数据块,而这个数据块正在被另一个用户从磁盘读取到内存中或者这个数据块正在被另一个会话修改时,当前的会话就需要等待,就会产生一个buffer busy waits等待。

            产生这些Latch争用的直接原因是太多的会话去访问相同的数据块导致热快问题,造成热快的原因可能是数据库设置导致或者重复执行的SQL 频繁访问一些相同的数据块导致。

 

 

            这个图是在我的buffer cache的那片blog 荡过来的。 结合这个图,我们来理解一下整个过程。数据块被加载到buffer cache,默认是加载到default pool。 那么Oracle 是通过Hash bucket 和 Hash Chain 来管理。

            将数据块分到不同的Hash bucket里,每个Hash bucket 对应一个Hash Chain。 每个Hash Chain 里保存了数据块的位置和它前后的List 信息。 而Hash Bucket 又是由Latches 进行控制,当我们想要找某个Hash bucket 上对应Hash Chain的数据块时,就要先拿到这个Latch。 如果很多session 去访问某一个数据块,就产生了热块,当session A 拿到Latch 后,在Session A 释放Latch 之前,其他Session 是拿不到这个Latch。因此,就产生了latch: cache buffers chains.的等待事件。

            也因为这个Latch的原因,也让并行的去访问某一个数据块成为困难的事。

 

            现在看一下,Session 拿到Latch 之后会做哪些操作。 这个联系x$bh 字典。在blog:

            Oracle Buffer Cache 原理

            ​​http://www.cndba.cn/Dave/article/1398​

 

里讲到,该字典记录了buffercache中每个block的情况。 当我们拿到latch 之后,Oracle 需要更新这个x$bh的信息。如:

(1)state:

(2)tch: tch is the touch count. A hightouch count indicates that the buffer is used often. Therefore, it willprobably be at the head of the MRU list.

(3)tim: touch time.

(4)class:represents a value designated for the use of the block.

(5)flag :is a bit array.

 

            x$bh字典表中的tch字段表示的就是block的touch count,一般来说这个值越高那么这个块就越热,我们称这样的块就叫做热点块。

            注意: user/all/dba_objects中的data_object_id关联x$bh中的obj或者是v$bh中的objd。

 

SYS@anqing1(rac1)> selectfile#,block#,status,objd from v$bh where block#=294838;

--block ID 号,之前查询过

 

    FILE#     BLOCK# STATUS        OBJD

---------- ---------- ------- ----------

        1     294838 scur         56204

 

xcur:表示这个块是排斥状态正在被当前的instance独占。
scur: 表示这个块正在被当前的instance共享
cr: 表示一致读
free: 表示块处在空闲状态
read: 表示正在从磁盘上读取块
write: 表示块正在被写出

 

--查看tch 最多的块

SYS@anqing2(rac2)> select * from (selectfile#,dbablk,tch from x$bh where obj=(select data_object_id from dba_objectswhere owner='SYS' and object_name='T1') order by TCH DESC) where rownum< 10;

 

    FILE#     DBABLK        TCH

---------- ---------- ----------

        1      74678        115

        1      74911        115

        6        144       115

        6        377        115

        1     294840        115

        1      73602        115

        1      75000        115

        6        233        115

        6        322        115

 

9 rows selected.

 

 

 

 

 

-------------------------------------------------------------------------------------------------------

Blog: ​​http://www.cndba.cn/dave​



DBA1 群:62697716(满);   DBA2 群:62697977(满)  DBA3 群:62697850(满)  

DBA 超级群:63306533(满);  DBA4 群: 83829929  DBA5群: 142216823   

DBA6 群:158654907  聊天 群:40132017   聊天2群:69087192

--加群需要在备注说明Oracle表空间和数据文件的关系,否则拒绝申请