暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

CBC热块等待

数据老匠 2016-06-10
509


关于CBC:

        在Buffer cache的巨大内存数据池中,存在着两个管理上的问题:数据进出、数据定位。


数据进出:

        Oracle对数据的操作均是在Buffer cache中进行的,因此,要对数据进行操作必须先将数据读入到Buffer cache当中去,这所谓进数据。

        但Buffer cache的大小总是有限的,这就要求在数据进入的同时还必须有一个通道保障数据可以正常排序,这所谓出数据。

        Buffer cache中使用LRU链来保障,数据的正常进出。LRU列表只与数据的进出顺序及冷热程度有关。


数据定位:

        当查找到数据以后,需要对内存中的某个数据进行定位。由于LRU列表只与数据的进出顺序及冷热程度有关,因此,并不具体定位查询数据的功能。

        Oracle为进行快速的数据定位,采用Hash排序算法对数据块进行管理。将这些经过HASH运行的数据块,首先分配到不同的Hash桶中,然后每一个Hash桶又存在着不同长度的Hash链,这里的Hash链就是Cache buffers chains。


CBC Latch:

        出现该等待的原因就是极短的时间内对少量数据块进行了过于频繁的访问。当一个进程在一个CBC上遍历数据时,有可能因为数据进出,导致该链的结构发生变化。

        如果遍历数据与数据链结构变化发生在同一时刻,就有可能会出现遍历到一条断链的情况,这就会使遍历的结果出现错误。

        为避免出现这种情况,在进程遍历某个CBC时,会同时为其加上一个Latch,由于Latch的排它性,因而此时其它的CBC Latch就必须等待。因此,CBC Latch发生的根本原因是因为热块的存在。




确定热点对象:

set long 5000 lines 200

col name for a25

col gets for 9999999999999999999

col misses for 9999999999999999999

col sleeps for 9999999999999999999

select latch#,name,gets,misses,sleeps from v$latch where name like 'cache buffer%';

        在这个查询结果里我们可以看到记录了数据库启动以来的所有cahce buffer chains的latch的状况。

        gets表示总共有这么多次请求,misses表示请求失败的次数(加锁不成功),而sleeps 表示请求失败休眠的次数,通过sleeps我们可以大体知道数据库中latch的竞争是否严重。由于v$latch是一个聚合信息,我们并不能获得哪些块可能存在频繁访问。


通过touch次数确定热点块:

set long 5000 lines 200

col owner for a15

col object_name for a35

col object_type for a20

select distinct owner, object_name, object_type

  from (select x.owner, x.object_name, x.object_type, y.tch

          from dba_objects x, x$bh y

         where x.data_object_id = y.obj

         order by y.tch desc)

 where rownum < 21;

        该SQL运行较快。


通过touch次数确定热点块:

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;


确定热块:

set long 5000 lines 200

col owner for a15

col segment_name for a20

col gets for 9999999999999999999

col misses for 9999999999999999999

col sleeps for 9999999999999999999

select distinct m.owner, m.segment_name, n.gets, n.misses, n.sleeps

  from dba_extents m,

       (select *

          from (select x.addr,

                       x.gets,

                       x.misses,

                       x.sleeps,

                       y.dbarfil,

                       y.dbablk

                  from v$latch_children x, x$bh y

                 where x.addr = y.hladdr

                   and x.name = 'cache buffers chains'

                 order by x.sleeps desc)

         where rownum < 21) n

 where m.RELATIVE_FNO = n.dbarfil

   and m.BLOCK_ID <= n.dbablk

   and m.block_id + m.blocks > n.dbablk;

该SQL运行较慢。




热块原因:

        一般来说,热点块会导致cache buffers chains竞争等待,但并不是说cache buffer chains一定是因为热点块而起。

        一般来说有两种可能:Latch数量、热块


Latch数量:

        在特别情况下CBC等待有可能是因为latch数量的问题导致的,也就是一个latch管理的buffers数量太多而导致竞争激烈。

        但是latch数量我们一般是不会轻易去设置的,这是oracle的隐藏参数。latch数量是通过参数_db_block_hash_latches 来定义的,一个latch对应的保护了多个buckets。

从8i开始,这个参数的default规则为:

        当cache buffers 少于2052 buffers

        _db_block_hash_latches = power(2,trunc(log(2, db_block_buffers - 4) - 1))

        当cache buffers多于131075 buffers

        _db_block_hash_latches = power(2,trunc(log(2, db_block_buffers - 4) - 6))

        当cache buffers位于2052与131075 buffers之间

        _db_block_hash_latches = 1024


优化SQL:

        不良的sql往往带来大量的不必要的访问,这是造成热点块的根源。不良的SQL,可能会导致大量的物理读和逻辑读,只有减少这些IO,就可以减少CBC Latch的问题。

        比如本该通过全表扫描的查询却走了索引的range scan,这样将带来大量的对块的重复访问。从而形成热点问题。再或者比如不当地走了nested loops的表连接,也可能对非驱动表造成大量的重复访问。

        这时需要找出物理读和逻辑读都很多的SQL并对其进行优化。


增加PCTFree的大小:

        如果一个表的PCTFree比较大,通常意味着这个表能够装的数据就比较少一些,这样就可以将这个块的数据访问压力减小。

        因此,可以改变PCTFree的大小。

        SQL> alter table TABX pctfree 20;



文章转载自数据老匠,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论