对于一个块,磁盘中叫block,内存中叫buffer。如何知道一个块是否‘在buffer cache中呢?oracle 采用的是hash算法。根据文件号块号来计算hash值,根据该值 定位到想用的bucket
每个hash bucket中都保存有一个指向cache buffer cache链表的链表头。
bucket ——> buffer head (file_id,block_id)
CBC链表
当某些块的hash值一样的时候,可以被组织成一个链表,bucket中存放的是指向链表的链表头。所以这个时候搜索buffer的过程多了一个从BH中提取BA,按照BA(buffer address)访问buffer
bucket ——> buffer head (file_id,block_id,BA)
找到 BH之后 要对BH进行加锁 buffer pin ,所以在申请访问链表前需先申请CBC latch。一般 一个CBC latch 要保护好几个bucket ,其持有模式决定于 对象类型(唯一索引,非唯一索引等)、块类型(根 ,叶)、操作(R W)、访问路径,除了唯一索引外,不管是W R CBC Latch都是以独占的模式持有。索引的根块和枝块只要不修改,都是以共享模式获得。 因为查询根块 枝块的频率很高,所以会导致 CBC Latch那里产生激烈的竞争。 优化:以共享的模式获取CBC Latch,不需要修改buffer pin的转态,出了普通的索引的根块 枝块外,在有唯一索引,索引唯一扫描的时候,索引的根块 枝块还有叶块 表块豆浆以共享的模式获取CBC Latch。 用rowid直接逻辑读 也是共享模式。
多个进程频繁的以不兼容的模式申请获得某一CBC Latch 访问此CBC Latch 保护的不同链表和不同的BH,这种现象为 热链竞争。latch:cache buffer chains
多个进程频繁的以不兼容的模式申请获得某一CBC Latch 访问此CBC Latch 保护的同一链表下的同一BH ,这种现象为热块竞争。Mutex相关竞争。
在v$bh中可以查看到特定文件和块的对应Latch,结合v$object可以查看对应具体的保护对象。
在buffer pin加锁的过程中是如何做到读不阻塞写的呢?因为在先发起的读操作 在修改了buffer pin 为s之后已经释放了CBC Latch ,此时写操作可以正常获取,修改读进程的BH并将其status标记为CR,这对读进程不产生影响。并且会克隆一个buffer status为XCUR。这是当写进程释放了CBC Latch 在独占的buffer pin的保护下修改buffer的时候,如果再有进程试图对XCUR的BH加共享的buffer pin ,则该进程会被阻塞,即产生了 buffer busy wait。这就是10g之后的读不阻塞写,写阻塞读。
如果在循环 写 和读 操作的系统中,读写session 都有可能出现BBW 写操作的BBW主要出现在回滚段块上,因为构造CR块时,读会话会在undo block上的buffer加更高级别的共享buffer pin 这种pin会阻塞 写会话向undo block中写入前印象数据。
通常CBC Latch 和buffer busy wait都是热块竞争,使用更小的块,增大pctfree或者重建表为hash 分区表。抬高高水位!
oracle修改一个buffer的步骤:
1>申请CBC Latch
2>获取独占的buffer pin
3>释放CBC Latch
4>生成redo(这个过程可以简单概述为:现在PGA中记录后映像数据,再传到共享池中,然后传到log buffer,如果log buffer没有空间,进程先会等待LGWR刷新log buffer中的空间,腾出空间后才能继续(这时进程会等待log buffer space事件))
5>修改buffer 中的内容
6>申请持有CBC Latch
7>释放独占buffer pin
8>释放CBC Latch