
关于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;





