ITPub博客

首页 > 数据库 > Oracle > Cache Buffer Chain Latch等待事件

Cache Buffer Chain Latch等待事件

原创 Oracle 作者:pxbibm 时间:2015-10-29 14:31:33 5 删除 编辑
  


产生的背景:

    Oracle为了将物理IO最小化,把最近使用过的数据块保持在内存中。为了管理这些内存,oracle 使用如图的结构,

Hash Chain的结构,Hash Chain位于共享池中,使用典型内存结构Bucket->Chain->Header结构进行管理。

Hash Chain结构的起点是Hash表,Hash表由多个hash bucket组成,块地址 是由file#+block#组成的,当扫描块时使用Hash函数

进行hash运算,使用hash值查找hash bucket,具有相同hash值的buffer haederhash bucket上以chain形式链接。

Buffer header有指向实际缓冲区的指针。注意:Hash Chain结构是在共享池中,而实际缓冲区信息存储在高速缓冲区中。

Hash Chain结构利用cache buffers chain Latch来保护。

当进程扫描特定的数据块时,必须获得相应数据块所在Hash Chain管理的cache buffers chain Latch。基本上

一个进程获得仅有的一个cache buffers chain Latch,一个cache buffers chain Latch管理多个Hash Chain

当多个进程同时检索Buffer Cache时,获得cache buffers chain Latch的过程中发生争用,就会产生

cache buffers chain Latch等待事件。
进程扫描特定的数据块整个过程。
  1、Oracle以每个块的文件号、块号和类型做HASH运算,得到HASH值。根据HASH值,到HASH表中取出指定块的内存地址 
  2、获取CBC Latch
  3、根据HASH值,搜索CBC链表
  4、根据DBA找到BH(Buffer Header)加Buffer Pin
  5、加完Buffer Pin马上释放CBC Latch
  6、访问Buffer开始fetch数据
  7、获取CBC Latch
  8、释放Buffer Pin
  9、释放CBC Latch

使用SQL语句可以获得hash_latcheshash_buckets数量,因此一个锁存器保护Bucket数量是1048576/32768=32个。

SQL> select x.ksppinm name,

  2         y.ksppstvl value,

  3         y.ksppstdf isdefault,

  4         decode(bitand(y.ksppstvf, 7),

  5                1,

  6                'MODIFIED',

  7                4,

              'SYSTEM_MOD',  8 

  9                'FALSE') ismod,

 10         decode(bitand(y.ksppstvf, 2), 2, 'TRUE', 'FALSE') isadj

 11    from sys.x$ksppi x, sys.x$ksppcv y

 12   where x.inst_id = userenv('Instance')

 13     and y.inst_id = userenv('Instance')

 14     and x.indx = y.indx

 15     and x.ksppinm like '%db_block_hash%'

 16   order by translate(x.ksppinm, ' _', ' ');


NAME        VALUE        ISDEFAUL ISMOD  ISADJ

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

_db_block_hash_buckets        1048576        TRUE     FALSE  FALSE

_db_block_hash_latches        32768        TRUE     FALSE  FALSE


产生的原因:

    1.执行效率低下的SQL,低效的SQL语句是发生Latch:cache buffers chains 争用的主要原因。发生在多个进程同时扫描大范围的表或索引时。

    2.出现热块hot block时,由于编写SQL语句时,SQL持续扫描少数特定块(between and ,in,not in, exists),多个会话同时执行SQL语句时,发生Latch:cache buffers chains 争用。
【案例1 Latch:cache buffers chains争用

--1.创建测试表
create table t1(id int,name varchar2(10));
insert into values(1,'xiaobo');
commit;
--2.获取t1表的第一行数据及ROWID,根据dbms_rowid包查出这行数据的文件号、块号

SQL> select rowid,
       dbms_rowid.rowid_relative_fno(rowid) file#,
       dbms_rowid.rowid_block_number(rowid) block#,
       id,
       name
  from emm.t1
 where rownum = 1;  2    3    4    5    6    7 

ROWID   FILE#   BLOCK#  ID NAME
------------------ ---------- ---------- ---------- --------------------
AAADfaAAFAAAACDAAA     5      131   1 xiaobo
注意:这里的DBA(Data Block Address)就是由5号文件和131号块组成

--3.根据DBA获取CBC Latch的地址

SQL> select hladdr from x$bh where file#=5 and dbablk=131;

HLADDR
----------------
00000001D1C266D8

--4.根据CBC Latch的地址可以查出这个CBC Latch被获得的次数

SQL> select addr,name,gets from v$latch_children  where addr='00000001D1C266D8';

ADDR                                        NAME                           GETS
----------------                          --------------------------------     -----------------------------------------------
00000001D1C266D8              cache buffers chains           46

--5.再次读取t1表的第一行数据,再次产生一次逻辑读
SQL>select id,name from emm.t1 where rowid='AAADfaAAFAAAACDAAA';
   ID      NAME
   --------            ------------
    1   xiaobo
--6.CBC Latch的次数变为48,说明一次逻辑读产生两次CBC Latch
SQL> select addr,name,gets from v$latch_children  where addr='00000001D1C266D8';
ADDR                                        NAME                           GETS
----------------                          --------------------------------     -----------------------------------------------
00000001D1C266D8              cache buffers chains           48

这里说明一次逻辑读要加两次CBC Latch,一次为了加Buffer Pin,一次为了释放Buffer Pin!
但是我不知道这里如何通过实验来证明,大家如果有好的建议,可以联系我。

使用oradebug跟踪CBC Latch争用事件

SQL> oradebug setmypid
Statement processed.
SQL> oradebug peek 0x1D1C266D8 4      -- 观察CBC Latch地址为0x1D1C266D8开始之后的4字节信息的值为0
[1D1C266D8, 1D1C266DC) = 00000000
SQL> oradebug poke 0x1D1C266D8 4 1   --修改CBC Latch地址为0x1D1C266D8开始的4字节信息的值为1,相当于获取了Latch
BEFORE: [1D1C266D8, 1D1C266DC) = 00000000 --修改前的值
AFTER: [1D1C266D8, 1D1C266DC) = 00000001   --修改后的值

--7. 再开一个新的会话,会话号为768

SQL> conn / as sysdba
Connected.
SQL> select sid from v$mystat where rownum=1;

       SID
----------
       768

 
--8.在新会话768T1的第一行,我观察到不会堵塞。但是我看网上有些网友写的博客说这里会产生堵塞。
这样的说法是不正确的。原因我会做完下个实验给大家解释,这里多说一句,大家看到网上的一些技术文章,一定
要自己动手做实验。如果发现和文章说明的不一样,一定要查阅资料。一直到搞清楚。
SQL>select id,name from emm.t1 where rowid='AAADfaAAFAAAACDAAA';
   ID      NAME
   --------            ------------
    1   xiaobo
 
--9.我们回到oradebug的会话,这次我们不是使用select语句,而使用update语句来获取latch

SQL> update emm.t1 set id=2 where rowid='AAADfaAAFAAAACDAAA';

1 row updated.

--10.再次使用oradebug模拟获取latch
SQL> oradebug setmypid
Statement processed.
SQL> oradebug poke 0x1D1C266D8 4 1
BEFORE: [1D1C266D8, 1D1C266DC) = 00000000
AFTER: [1D1C266D8, 1D1C266DC) = 00000001


--11.回到刚才768会话下,T1的第一行,这时我观察到产生了堵塞
SQL>select id,name from emm.t1 where rowid='AAADfaAAFAAAACDAAA';


--12.我们再开第三个会话,查看会话号768的等待事件,我们看到产生了CBC Latch的等待事件

SQL> select sid,event,p1raw,p2raw,p3raw from v$session where sid=768;

       SID        EVENT                               P1RAW                      P2RAW                   P3RAW
----------------   -------------------------------------  -------------------------        ---------------------------     -------
       768      latch: cache buffers chains    00000001D1C266D8    00000000000000B1    00

最后在第一个会话中释放lacth
SQL> oradebug poke 0x1D1C266D8 4 0
BEFORE: [1D1C266D8, 1D1C266DC) = 00000001
AFTER: [1D1C266D8, 1D1C266DC) = 00000000
总结:
在获取保护hash bucket的cache buffers chains latch时,如果是读取工作(select),就以shared模式获
得(这也是我们刚才在实验中select时没有产生争用的原因)。如果是修改工作(update),就以exclusive模式
获得。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/12798004/viewspace-1818231/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
  • 博文量
    240
  • 访问量
    2174180