HASH链表

Oracle内核技术揭密_吕海波  学习笔记

一,HASH链表与逻辑读

oracle要从高速缓冲区中拿到5号文件1234号块buffer的信息,就需要使用到HASH算法。
Buffer Cache:高速缓冲区中包含多个buffer,每一个buffer就记录一个数据块对应的缓冲信息。
Buffer Header:每一个Buffer Cache都有一个Buffer Header(BH),它用来记录这个高速缓冲区中所有的buffer address(BA),通过BA可以定位到缓冲区中的buffer。
Buffer Bucket:它里面只记录一系列Buffer Header双向链的链表头信息,oracle通过文件号和块号计算出HASH值,来定位到相应的Bucket,当不同Buffer Header下的buffer计算HASH值发生冲突时就会定位到同一个bucket,这时多个Buffer Header会构成一个双向链,叫cache buffer chain链表(CBC链表),并将链表头信息记录在bucket中。

Bucket数量由隐藏参数_db_block_hash_buckets决定:

SQL> SELECT   ksppinm, ksppstvl, ksppdesc FROM   x$ksppi x, x$ksppcv y WHERE   x.indx = y.indx AND  ksppinm = '_db_block_hash_buckets';

KSPPINM                    KSPPSTVL      KSPPDESC
----------------------     ---------    -------------------------------------
_db_block_hash_buckets     262144        Number of database block hash buckets

HASH链表_第1张图片
搜索buffer步骤如下:
1,进程根据要访问块的文件号和块号,计算HASH值得到到数字X。
2,根据HASH值X,定位到相应HASH Bucket,如BucketX。
3,搜索Bucket后的链表,查找哪个Buffer Header(BH)是目标BH。
4,找到目标BH后,从中取出Buffer的Buffer Address(BA)。
5,按BA访问Buffer

上述为oracle逻辑读的过程,如果搜索Bucket后的BH链表,没有找到包含目标块的BH,就说明目标块不在缓存中,只能物理读了。

二,catch buffer chain latch 与buffer pin 锁

 SGA是公共内存,因此在访问buffer时是需要锁保护机制的,oracle采用的锁机制是latch和mutex。

正常情况下一个bucket后面的catch buffer chain就需要一个catch buffer chain latch来保护,但latch也是占用空间的,于是oracle这里是一个CBC  latch负责多个bucket的锁管理。一个latch的大小为192字节:

SQL> select to_number(b.addr,'xxxxxxxxxxxxxxxxxxxxx')- 
            to_number(a.addr,'xxxxxxxxxxxxxxxxxxxxx')
     from (select rownum rid,addr from v$latch_children where name='cache buffers chains' order by addr) a,
          (select rownum rid,addr from v$latch_children where name='cache buffers chains' order by addr) b 
     where a.rid=b.rid+1 and rownum <=1;

TO_NUMBER(B.ADDR,'XXXXXXXXXXXXXXXXXXXXX')-TO_NUMBER(A.ADDR,'XXXXXXXXXXXXXXXXXXXX
--------------------------------------------------------------------------------
                                                                             192

HASH链表_第2张图片

当我们搜索CBC链表时,需要先获取CBC latch进行锁保护;当找到目标所在BH,访问buffer前要修改buffer pin进行锁保护,修改完buffer pin后就可以释放CBC latch ,后续的buffer访问只需要在buffer pin保护下进行即可;当访问完buffer需要释放buffer pin时,这时又需要CBC latch 来保护。CBC latch的功能就是保护CBC链的访问和buffer pin的修改。

buffer pin锁有多种模式,常见的为共享模式(S)和独占模式(X)。在没有加锁时buffer pin值为0。

CBC latch也有共享和独占两种模式,模式的选择取决于以下4个要素:

1)对象类型(唯一索引,非唯一索引等)

2)块类型(根块,叶块,表块等)

3)操作(读,修改)

4)访问路径

对于一般的逻辑读,我们在读取buffer信息前都需要修改buffer pin值,这时的CBC latch基本都是独占锁。步骤如下:

HASH链表_第3张图片

HASH链表_第4张图片

 HASH链表_第5张图片

 HASH链表_第6张图片

 当我们要访问索引的叶块时,需要频繁的访问它的根块和枝块,但对根块和枝块修改的频繁度又很低,这时没有必要使用独占模式的CBC latch。优化后的步骤如下:

HASH链表_第7张图片

 

 HASH链表_第8张图片

HASH链表_第9张图片

 

 HASH链表_第10张图片

 

 可以看到在CBC latch 共享模式中搜索CBC链表和访问buffer,中间没有修改buffer pin,也没有释放CBC latch,这样CBC latch的加载时间比独占模式要长,但它缓解了独占模式下的争用。

在有唯一索引、唯一索引扫描情况时,根块、枝块、叶块、表块都是使用共享模式的CBC latch。也就是说当唯一索引使用‘where  id = ?’这样的等值条件查询时,就使用共享模式的CBC latch;当使用的是范围查询时,则和非唯一索引一样,只有根块、枝块共享模式的CBC latch,不修改buffer pin,而叶块、表块还是使用独占模式的CBC latch。可以理解为使用索引唯一访问路径时,所有块的访问都是共享模式的CBC latch;另外,rowid方式直接逻辑读表块时是使用独占模式的CBC latch。

除了唯一索引外,在多数情况下,读或者写表块,都是使用独占模式的CBC latch。

另外根块和枝块,只要不修改,就使用共享模式的CBC  latch。

 

你可能感兴趣的:(HASH链表)