oracle Latch: cache buffers chain争用定位
一、原理
即当对数据库中同一块的并发访问极高时,会发生等待事件“Latch: cache buffers chain”。对块的访问通常是一个快速操作,但如果并发用户足够快地重复访问块,则对该块的简单访问可能会成为瓶颈。当多个用户在表上运行嵌套循环连接并访问通过索引驱动的表时,最常见的 cbc(缓存缓冲区链)闩锁争用发生。
数据库中访问数据块过程如下:
- 进程根据要访问块的文件号、块号,计算HASH值。
- 根据HASH值找到HASH Bucket。
- 搜索Bucket后的链表,查找哪个BH是目标BH。
- 找到目标BH,从中取出Buffer的BA。
- 按BA访问Buffer。
搜索Bucket后的链表,还有访问BH中的BA,都需要Latch的保护。这个Latch就是Cache Buffers Chain Latch(简称CBC Latch)。
CBC Latch也有两种持有模式:共享和独占。但要注意的是,不同于Buffer Pin锁用读、写形式来决定锁的模式,就算为了“读”而持有CBC Latch,有时会是独占模式,而有时则会是共享模式。
CBC Latch的持有模式取决以下4个要素:
- 对象类型(唯一索引、非唯一索引等)。
- 块类型(根块、叶块或表块等)。
- 操作(读、修改)。
- 访问路径(Accees Path)。
前面所提的流程一直都是独占CBC Latch的。除有唯一索引外,在大多数情况下,无论是读还是写,访问表块都将以独占模式获得CBC Latch。
出现CBC Latch等待的可能情况
- 多个进程频繁地以不兼容的模式申请获得某一CBC Latch,访问此CBC Latch保护的不同链表和不同BH。
- 多个进程频繁地以不兼容的模式申请获得某一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,重新计算后很可能就不在同一链表中了。
二、定位
- 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(*)
/