cache buffers chains

cache buffers chains 看名字像是一个链表结构,但实际上它是一个latch。 要理解它,首先要理解下面的概念。

  • hash bucket
  • hash chain list

hash bucket和hash chain list是用来在data buffer里快速定位数据块的。oracle在访问一个数据块之前,首先会根据数据块的地址生成一个hash值。通过这个hash值,oracle可以快速的找到一个hash bucket(顾名思义,hash bucket就是一系列的桶,每一个桶都对应着一个hash值)。但是如果有多个数据块计算得出的hash值相等,那么oracle在访问他们的时候就会找到相同的hash bucket。这些数据块的header被组织到一个叫做hash chain list的链表中,该链表就放在这个hash bucket中。通过数据块的header,你可以找到数据块在buffer中的位置。总结一下就是,

  1. 通过data block address 计算出hash value
  2. 通过hash value定位到hash bucket
  3. 通过hash bucket中的hash chain list找到该hash bucket中所有数据块的header
  4. 通过数据块的header找到数据块

上面的图列出了访问data block的大概流程,但是可以看到在hash bucket之前还要访问一个 latch。这个latch就是我们开篇提到的 cache buffer chain。 这种latch一个管理着多个hash bucket,你只有获得了这样一个latch才能继续访问hash bucket,同其他latch存在的意义一样,该latch也是为了控制资源的并发访问。想象一下,如果没有该latch,两个进程在同一时间去修改 data buffer中的一个地址,可能就会导致出错。ok,我们需要重新梳理一下,因为这些名字都很像,会导致混乱。

cache buffer chain:是一个latch 保护 hash bucket

hash bucket:通过计算数据块的地址可以得到一个哈希值,通过该哈希值可以定位到一个hash bucket

hash chain list:是一个存放于hash bucket中的链表,链表上是该hash bucket中数据块的header

我们通过数据块的地址得到一个哈希值,通过该哈希值定位到一个hash bucket,在访问该hash bucket之前要先得到该hash bucket的latch,获得latch后访问hash bucket,进而访问hash chain list,获得若干数据块header,进而访问数据块。
View Code

梳理完毕,额外说一下,hash bucket的数量由隐藏参数 _db_block_hash_buckets控制。

了解了上面的内容后,我们就应该明白,当出现latch:cache buffers chains这样的等待事件的时候是怎么回事。这种等待是因为多个进程争用 同一个latch,也就意味着多个进程在争用同一个hash bucket,在争用同一个数据块。 还有一种可能是系统中有 BUFFER_GETS(逻辑读取) 很高的sql语句。(说实话第二种可能我不太明白。解答:仍然不确定,但猜想是这样的,cr读一般是指对一个数据块产生多个cr block。由于这些cr block都是同一个data block产生的,因而他们都对应着一个hash bucket自然就对应着一个cache buffer chain latch) 这时候我们可以用如下方法来 trouble shooting。

1. 检查逻辑读较高的sql语句 也就是找到v$sql中BUFFER_GETS/EXECUTIONS大的语句。

select * from (select sql_text,hash_value,buffer_gets/executions from v$sql where executions<>0 and hash_value in (select sql_hash_value from gv$session where status='ACTIVE' )order by buffer_gets/executions desc ) where rownum<16;

2. 查看v$latch,看自实例启动以来cache buffers chains锁存器争用是否厉害

select round((misses/gets)*100)||'%',round(100*(immediate_misses/(immediate_gets+immediate_misses)))||' %' from v$latch where name='cache buffers chains';

对于willing-to-wait,比较重要的是misses/gets,假如大于1%就应该发生争用了,大于10%,就有争用严重的情况了。对于no-wait模式immediate_misses/(immediate_gets+immediate_misses)也一样。(这一段是从网上copy过来的,不是太懂这个SQL的具体意义,不过这个查询的目的应该是判断系统的hash bucket设置是否正确吧)

3. 查询v$latch_children看是否有热块,并获取对应latch的addr

select * from (select addr,child#,gets,misses,sleeps from v$latch_children where name='cache buffers chains' order by sleeps desc ) where rownum<=20;

如果存在倾斜明显,即某些子锁存器的GETS与SLEEPS比其他子锁存器高很多,则可以推测相应锁存器管辖的chain上有Hot Block。然后通过子锁存器地址,即v$latch_children的addr字段,来获取这些子锁存器所管理的对象的文件号块号与热度。

select hladdr,obj,(select object_name from dba_objects where (data_object_id is null and object_id=x.obj) or data_object_id=x.obj and rownum=1) as object_name,dbarfil,dbablk,tch
from x$bh x
where hladdr in ('00000000DA253C08','00000000DA380310') order by tch desc;

注意x$bh字典表中的tch字段表示的就是block的touch count,一般来说这个值越高那么这个块就越热,我们称这样的块就叫做热点块。接下来根据FILE#,dbablk来找出对应对象。

select * from dba_extents where file_id=10 and 36643122 between block_id and block_id + blocks - 1;
 
4. 直接通过v$bh视图直接查找数据库热点块,从而找到热点的对象。
select * from (select hladdr,ts#,file#,dbarfil,dbablk,tch from x$bh order by tch desc) where rownum<16;
然后通过dba_extents来查找相应对象。
select * from dba_extents where file_id=10 and 36643122 between block_id and block_id + blocks - 1;

出现热块的解决办法

1.优化SQL,如优化nested loop join,如果有可能使用hash join代替nested loop join。
2.可以利用对热块索引进行hash分区,或者使用hash簇的方式减缓热块现象。
3.调整表的pctfree值,将数据尽可能的分布到多个块中,但相同的查询要扫更多块,有负面作用。
4.并行查询是直接读数据文件,不经过SGA,即direct path read,所以就不存在锁存器争用的情况了。但其一般是为了大量数据读取而使用的,不作为一般的解决方案。
5.等问题自己消失。有时当出现latch争用时,故障时刻确实没有较好的方式解决,找到病因才是关键。

下面的内容是从oracle的官方文档(Performance tunning guide)上copy的,可以一读。

10.3.10.3.5 cache buffers chains

The cache buffers chains latches are used to protect a buffer list in the buffer cache. These latches are used when searching for, adding, or removing a buffer from the buffer cache. Contention on this latch usually means that there is a block that is greatly contended for (known as a hot block).

To identify the heavily accessed buffer chain, and hence the contended for block, look at latch statistics for the cache buffers chains latches using the view V$LATCH_CHILDREN. If there is a specific cache buffers chains child latch that has many more GETS, MISSES, and SLEEPS when compared with the other child latches, then this is the contended for child latch.

This latch has a memory address, identified by the ADDR column. Use the value in the ADDR column joined with the X$BH table to identify the blocks protected by this latch. For example, given the address (V$LATCH_CHILDREN.ADDR) of a heavily contended latch, this queries the file and block numbers:

SELECT OBJ data_object_id, FILE#, DBABLK,CLASS, STATE, TCH
  FROM X$BH
 WHERE HLADDR = 'address of latch'
  ORDER BY TCH;

X$BH.TCH is a touch count for the buffer. A high value for X$BH.TCH indicates a hot block.

Many blocks are protected by each latch. One of these buffers will probably be the hot block. Any block with a high TCH value is a potential hot block. Perform this query several times, and identify the block that consistently appears in the output. After you have identified the hot block, query DBA_EXTENTS using the file number and block number, to identify the segment.

After you have identified the hot block, you can identify the segment it belongs to with the following query:

SELECT OBJECT_NAME, SUBOBJECT_NAME
  FROM DBA_OBJECTS
 WHERE DATA_OBJECT_ID = &obj;

In the query, &obj is the value of the OBJ column in the previous query on X$BH.

 另外,从x$bh中我们可以看到hash chain list的相关信息

SQL> desc x$bh
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 ADDR                                               RAW(8)
 HLADDR                                             RAW(8)
 NXT_HASH                                           RAW(8)
 PRV_HASH                                           RAW(8)
 NXT_REPL                                           RAW(8)
 PRV_REPL                                           RAW(8)

But, of course, this is not the whole x$bh. Actually from below picture you can understand more clearly.

原文地址:https://www.cnblogs.com/kramer/p/3008288.html