Buffer Cache ---- HASH链

本文深入探讨了Oracle的Buffer Cache中HASH链的工作原理,包括如何保证数据一致性、链表结构及其示例分析,以及如何通过实验查看和理解HASH链。通过分析高争用的cache buffers chains闩锁,强调了检查高逻辑读SQL和热块冲突的重要性。
摘要由CSDN通过智能技术生成
一、HASH链理解
1、HASH链是ORACLE为了提高数据块定位速度而设计的。将db cache中正在使用的数据块都放到HASH链上,这个HASH链是多个BUCKET组成的多链结构,每个BUCKET就是一条链的链头,从而引出一条独立的双向链。ORACLE设计了一个散列算法,通过数据文件的文件号和数据块的块号,进行散列运算,得到的散列值就是这个数据块所在的BUCKET号码。得到BUCKET位置后就可以很快地找到链头,从链头的双向链表扫描下去,即可以找到相关的数据块。Bucket数量是固定的一旦数据库启动后就不会改变,BUCKET数量由隐含参数 _DB_BLOCK_HASH_BUCKET确定。8i的默认值是2*DB_BLOCK_BUFFERS,9i的默认值是大于两倍的DB Block Buffer数量的最小的2的幂次的数值。虽然ORACLE的每个版本对该参数的定义不同,但是有一点是不变的,就是数据库缓冲区的Hash Chains的BUCKET的数量始终大于DB Buffer数量的两倍。虽然我们无法获得ORACLE内部散列算法的详细细节,但是有一点可以肯定的,ORACLE设计HASH链的基本思路是,每个链上有最少的BUFFER数量,最佳的情况是每条链上只有一个BUFFER.

2、访问HASH链时,为了保证数据访问的一致性,通过cache buffers chains闩锁来保护Hash链的数据结构。因此如果出现cache bufers chains闩锁争用,那么一般来说都和HASH链的访问有关。如果碰到该闩锁等待严重,首先应该检查是否存在逻辑读(buffer get)十分高的SQL,看看这些SQL的执行计划是否存在问题,是否对大表做了全表扫描。此外较严重的热块冲突也会加大cache buffers chains闩锁的争用,这一点需要注意。

二、HASH链示意图


BUCKET是存放在共享池中的,CBC是存放在db cache 中的。所以,当增大db cache时应考虑是否需要增大shared pool。相同的文件号块号(即相同DBA)通过散列算法会分布在一个BUCKET上,所以CR读的块肯定和当前值块在一个CBC链上。

三、做实验查看HASH链
1、创建测试表(普通用户下)
create table panda_t2(id int,name varchar2(100));

begin
  for i in 1 .. 90000
    loop 
      insert into panda_t2 values(i,'panda'||i);
    end  loop;
  commit;
end;
/
2、表中数据对于的文件号和块号(普通用户下)
SQL> select dbms_rowid.rowid_relative_fno(rowid) file#,dbms_rowid.rowid_block_number(rowid) block#,id,name from panda_t2 where rownum<50;

     FILE#     BLOCK#      ID NAME
---------- ---------- ---------- -----------------------------------------------------
4           171    460           panda460
4           171    461           panda461
4           171    462           panda462
4           171    463           panda463
4           171    464           panda464
注:
4 ,171 ===DBA (DATA BLOCK ADDRESS)
rdba(relative data block address)相对地址

3、查询4号文件171号块对应的bh地址(DBA用户下操作)
SQL> select lower(ba) from x$bh where FILE#=4 and DBABLK=171; 

LOWER(BA)
--------
407a6000

注:
rowid 6+3+6+3(对象号+文件号+数据块号+记录槽号)  rbms_rowid的包在官方文档的pl/sql里有说明

rdba(relative data block address)相对地址

bh中含有dba(数据在磁盘上的物理地址)与ba(数据在内存上的buffer地址)的映射关系

4、把整个buffer的BH转储出来
SQL> alter session set events 'immediate trace name buffers level 1';
Session altered.

得到转储文件(Default trace file)
SQL> select * from v$diag_info where name = 'Default Trace File';

   INST_ID NAME VALUE
---------- -------------------- -----------------------------------------------------------
1 Default Trace File/u01/app/oracle/diag/rdbms/panda/panda/trace/panda_ora_2829.trc

这里贴出一个BH作为示例:
BH (0x407fa1f4) file#: 4 rdba: 0x010000ab (4/171) class: 1 ba: 0x407a6000
  set: 3 pool 3 bsz: 8192 bsi: 0 sflg: 2 pwc: 116,19
  dbwrid: 0 obj: 73419 objn: 73419 tsn: 4 afn: 4 hint: f
  hash: [0x4e381510,0x4e381510] lru: [0x407fa374,0x407fa1cc]
  ckptq: [NULL] fileq: [NULL] objq: [0x407fa38c,0x407fa1e4]
  st: XCURRENT md: NULL tch: 2
  flags: only_sequential_access
  LRBA: [0x0.0.0] LSCN: [0x0.0] HSCN: [0xffff.ffffffff] HSUB: [65535]
  cr pin refcnt: 0 sh pin refcnt: 0

注:
rdba: 0x010000ab==>4号文件171号块(转换为二进制,前十位代表文件号,后22位代表块号。所以为4号文件171号块)
0x010000ab==>0000 0001 00(前十位)==>4

后22位:
SQL> select to_number('ab','xxxxxxxxxxxxx') from dual;

TO_NUMBER('C3','XXXXXXXXXXXXX')
-------------------------------
                            171

hash: [0x4e381510,0x4e381510]:上面贴出来的这个,发现里面的地址是一样的,这个很有意思。一样的原因是这个bh所在的hash链只有一个bh。
0x4e381510这个地址都指向了BUCKET(BUCKET是存放在shared pool里的)

5、查询出4号文件171号块的BA,NXT_HASH,PRV_HASH和BH的地址范围(在DBA用户下执行)

SQL> select lower(ba) ,lower(NXT_HASH),lower(PRV_HASH) from x$bh where FILE#=4 and DBABLK=171
LOWER(BA LOWER(NX LOWER(PR
-------- -------- --------
407a6000 4e381510 4e381510

SQL> select lower(min(ba)),lower(max(ba)) from x$bh;

LOWER(MI LOWER(MA
-------- --------
3f0f2000 44be0000

可以看到4e381510是不在BH地址范围的,说明4e381510指的不是BH。从一个方面验证了当hash: [0x4e381510,0x4e381510]的两个地址相同时,说明这个BUCKET只挂了一个BH,这个BH的NXT_HASH和PRV_HASH指向它的BUCKET;
6、找一个Cache Buffer Chain(CBC)多于一个BH的链(即找一个hash[]中地址不一样的BH所在的CBC)
查看了刚才dump出来的/u01/app/oracle/diag/rdbms/panda/panda/trace/panda_ora_2829.trc文件,找了半天没找到有hash[]不一样BH。
这验证了前面的一句话 “ORACLE设计HASH链的基本思路是,每个链上有最少的BUFFER数量,最佳的情况是每条链上只有一个BUFFER”

为了得到一条多BH的CBC链,我修改一条数据(因为修改前后的数据的文件号和块号是一样的,所以他们的BH会在一个CBC上)
SQL>  update panda_t2 set name = 'panda_update' where id=464;
1 row updated.


SQL> commit;
Commit complete.

SQL> select lower(ba) from x$bh where FILE#=4 and DBABLK=171;
#这个查询结果有两条是因为有个CR块
LOWER(BA
--------
3e980000
407a6000

SQL> select lower(ba) ,lower(NXT_HASH),lower(PRV_HASH) from x$bh where FILE#=4 and DBABLK=171;
#这个查询结果有两条是因为有个CR块
LOWER(BA LOWER(NX LOWER(PR
-------- -------- --------
3e980000 407fa270 4e381510
407a6000 4e381510 3ebebeb4

SQL> select lower(min(ba)),lower(max(ba)) from x$bh;
#这个的lower(min(ba))和上面的不一样是应为BH增加了,所以BH的ba范围变大了
LOWER(MI LOWER(MA
-------- --------
3e6d6000 44be0000

SQL> alter session set events 'immediate trace name buffers level 1';
Session altered.

SQL> select * from v$diag_info where name = 'Default Trace File';

   INST_ID NAME       VALUE
---------- ------------------  ---------------------------------------------------------------
1     Default Trace File  /u01/app/oracle/diag/rdbms/panda/panda/trace/panda_ora_2829.trc

#这个是修改后的值,CLASS:1 代表数据块,st: XCURRENT 这个代表当前值
BH (0x3ebebe38) file#: 4 rdba: 0x010000ab (4/171) class: 1 ba: 0x3e980000
  set: 3 pool 3 bsz: 8192 bsi: 0 sflg: 2 pwc: 250,28
  dbwrid: 0 obj: 73419 objn: 73419 tsn: 4 afn: 4 hint: f
  hash: [0x407fa270,0x4e381510] lru: [0x3ebebfb8,0x3ebebe10]
  obj-flags: object_ckpt_list
  ckptq: [0x44bfab10,0x3ebec25c] fileq: [0x4dc629f8,0x4dc629f8] objq: [0x4a479a34,0x4a479a34]
  st: XCURRENT md: NULL tch: 2
  flags: buffer_dirty redo_since_read
  LRBA: [0x9.142e.0] LSCN: [0x0.d7253] HSCN: [0x0.d7253] HSUB: [1]

#这个是修前的值,CLASS:1 代表数据块,st: CR 这个代表CR块(为了满足数据库的一致性,为CR读提供的)   
BH (0x407fa1f4) file#: 4 rdba: 0x010000ab (4/171) class: 1 ba: 0x407a6000
  set: 3 pool 3 bsz: 8192 bsi: 0 sflg: 2 pwc: 250,28
  dbwrid: 0 obj: 73419 objn: 73419 tsn: 4 afn: 4 hint: f
  hash: [0x4e381510,0x3ebebeb4] lru: [0x4dc608d8,0x447f8c44]
  lru-flags: moved_to_tail
  ckptq: [NULL] fileq: [NULL] objq: [NULL]
  st: CR md: NULL tch: 2
  cr: [scn: 0x0.d724f],[xid: 0x0.0.0],[uba: 0x0.0.0],[cls: 0x0.d724f],[sfl: 0x0],[lc: 0x0.cf33b]
  flags: only_sequential_access

上面的这两个BH在HASH链上是相互指向的,第一个的0x407fa270指向的是第二个BH(0x407fa1f4)的中间位置,第二个的0x3ebebeb4指向的是第一个BH(0x3ebebe38)中间位置。

0x407fa270-0x407fa1f4=0x7C=124

0x3ebebeb4-0x3ebebe38=0x7C=124

在HASH链上的BH的相互指向不是指向的是另一个BH的地址的头部,而是指向了BH的中间部分。(11G 对于32位系统指向的位置比BH地址偏移个124,对于64为系统偏移是176)
从前面查询x$BH的NXT_HASH和PRV_HASH可以得到这样的结论hash: [NXT_HASH,PRV_HASH](即第一个位置放的是NXT_HASH,第二个位置放的是PRV_HASH)
对比上面两个BH信息,发现当前值的BH是挂在CBC的头部,修改前的值是挂在CBC的尾部


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值