oracle Latch: cache buffers chain争用定位

一、原理

即当对数据库中同一块的并发访问极高时,会发生等待事件“Latch: cache buffers chain”。对块的访问通常是一个快速操作,但如果并发用户足够快地重复访问块,则对该块的简单访问可能会成为瓶颈。当多个用户在表上运行嵌套循环连接并访问通过索引驱动的表时,最常见的 cbc(缓存缓冲区链)闩锁争用发生。

数据库中访问数据块过程如下:

  1. 进程根据要访问块的文件号、块号,计算HASH值。
  2. 根据HASH值找到HASH Bucket。
  3. 搜索Bucket后的链表,查找哪个BH是目标BH。
  4. 找到目标BH,从中取出Buffer的BA。
  5. 按BA访问Buffer。
    搜索Bucket后的链表,还有访问BH中的BA,都需要Latch的保护。这个Latch就是Cache Buffers Chain Latch(简称CBC Latch)。

CBC Latch也有两种持有模式:共享和独占。但要注意的是,不同于Buffer Pin锁用读、写形式来决定锁的模式,就算为了“读”而持有CBC Latch,有时会是独占模式,而有时则会是共享模式。
CBC Latch的持有模式取决以下4个要素:

  1. 对象类型(唯一索引、非唯一索引等)。
  2. 块类型(根块、叶块或表块等)。
  3. 操作(读、修改)。
  4. 访问路径(Accees Path)。
    前面所提的流程一直都是独占CBC Latch的。除有唯一索引外,在大多数情况下,无论是读还是写,访问表块都将以独占模式获得CBC Latch。

出现CBC Latch等待的可能情况

  1. 多个进程频繁地以不兼容的模式申请获得某一CBC Latch,访问此CBC Latch保护的不同链表和不同BH。
  2. 多个进程频繁地以不兼容的模式申请获得某一CBC Latch,访问此CBC Latch保护的同一链表下的同一BH。

热链竞争最容易解决。多个进程其实访问的是不同的BH,只不过恰好这些BH在同一CBC Latch保护下(这种巧合的情况当然比较少见,但偶尔也会遇到),这时,解决方案很简单,可对两个隐藏参数中的一个进行修改,即_db_block_hash_buckets和_db_block_hash_latches,它们分别控制HASH Bucket的数量和CBC Latch的数量。这样一来,BH和HASH Bucket的对应关系就会被重新计算。原本在同一链表中的BH,重新计算后很可能就不在同一链表中了。

二、定位

  1. sql

select count(*), sql_id, nvl(o.object_name,ash.current_obj#) objn, substr(o.object_type,0,10) otype, CURRENT_FILE# fn, CURRENT_BLOCK# blockn from v$active_session_history ash , dba_objects o where event like 'latch: cache buffers chains' and o.object_id (+)= ash.CURRENT_OBJ# group by sql_id, current_obj#, current_file#, current_block#, o.object_name,o.object_type order by count(*) /