Buffer cache学习(二)

和BUFFER CACHE相关的主要Latch有:cache buffer lru chain、cache buffers chains

buffer cache就是一块含有许多数据块的内存区域,这些数据块主要都是数据文件里的数据块内容的拷贝,那么数据的查询和修改都要通过它来完成。接下来就看看访问数据的流程是怎样的

1 :当一个进程要访问数据时,首先要查找BUFFER CACHE看看数据是否已经存在? 
(Y) 如果数据在BUFFER CACHE中存在,则根据数据的状态来判断是否可以直接访问还是需要构造一致性读取? 
(N) 如果数据在BUFFER CACHE中不存在,则需要从数据文件中读取数据块到BUFFER CACHE中去。这个时候,需要查找在BUFFER CACHE中寻找足够的内存空间来读取相关的数据。

2 :现在BUFFER CACHE那么大,一个BUFFER一个BUFFER的扫描过去是相当的消耗资源以及查询的时间,那我们怎样才能快速地查到数据了? 可以看看下面关于BUFFER CACHE的示图:


2.1图中右边的有一块Buffers Memory,其中每一块小格就是一个Buffer(用来存放从数据文件中读取的数据块Block)

2.2图中左边的有许多Buffer Header用线指向Buffers Memory中的相应:Buffer。 

2.3:图中左边的有许多实线箭头,这些箭头(其实就是数据结构的链表结构中的指针)将不同的Buffer Header连接成一条Hash Chain,这边也就是Cache Buffers Chain(双向链表。 

2.4:另外,还有一个Hash: Bucket,其实这只是一个逻辑上的概念,即每一个HashBucket都会有一条Hash Chain来将Buffer Header(按照HASH算法分类后)连接起来,并由一个Cache Buffers Chains Latch来进行管理其并发操作。

每当将一个Block读入到Buffer Cache的时候,首先会构造一个与之对应的Buffer Header,然后根据HASH算法( Hash Bucket = MOD(Data Block Address, _DB_BLOCK_HASH_BUCKETS) ),将Buffer Header放到对应的Hash Bucket的Cache Buffers Chain中去,并在Buffer Header中记录如下信息


1).存放该Block在Buffer Cache中实际存储地址 
2).存放该Block的类型(data,segment header,undo header,undo Block等类型) 
3).由于此Buffer Header 所在的Hash Chain,是通过在Buffer Header保存指向前一个Buffer Header的指针和指向后一个Buffer Header的指针方式实现,所以还存指针 

4).存储lru,lruw,ckptq等队列,一样是通过记录前后Buffer Header指针方式实现

5).当前该Buffer Header所对应的数据块的状态以及标记 

6).该Buffer Header被访问的次数(touch次数) 
7).正在等待该Buffer Header的进程列表(waiter list)及正在使用此Buffer Header的(user list)

 

2.5:最后,在看看Hash Latch,即Cache Buffers Chains Latch,在Oracle 8i之前,对应每一个Hash Bucket,Oracle使用一个独立的Latch来维护。Oracle 8i开始,Oracle增加了Hash Bucket的数量,这样每个Latch需要维护多个Bucket,由于每个Hash Bucket 上的Buffer Header数量大大减低,也使得Latch的性能反而提高。其中,BUFFER CACHE中Hash Bucket的个数由隐含参数_db_block_hash_buckets决定,Cache Buffers Chains Latch的个数由隐含参数_db_block_hash_latches决定。

SYS@ prod>select count(*) from x$bh; --用这句查出buffer的个数,

  COUNT(*)
----------
     13322

查询隐含参数可参考


select

x.ksppinm  name,

 y.ksppstvl  value,

 y.ksppstdf  isdefault,

 decode(bitand(y.ksppstvf,7),1,'MODIFIED',4,'SYSTEM_MOD','FALSE')  ismod,

 decode(bitand(y.ksppstvf,2),2,'TRUE','FALSE')  isadj

from

 sys.x$ksppi x,

 sys.x$ksppcv y

where

 x.inst_id = userenv('Instance') and

 y.inst_id = userenv('Instance') and

 x.indx = y.indx and

 x.ksppinm like '%_&par%'

order by

 translate(x.ksppinm, ' _', ' ')

/

 

NAME                                     VALUE      ISDEFAULT ISMOD      ISADJ

-------------------------------------------------- --------- ---------- -----

_db_block_hash_buckets                   32768      TRUE     FALSE      FALSE

_db_block_hash_latches                   1024       TRUE     FALSE      FALSE

 

关于_db_block_hash_buckets参数的取值:据说在8i下,该参数缺省db_block_buffers×2;但是到了9i以后,该参数似乎取的是小于且最接近于db_block_buffers×2的素数。
在ORACLE 10G和11G中,默认值是大于2倍的buffer数量的最小的2的幂的值。举例如buffer数量是13322,2倍就是26644,那么大于26644的最小的2的幂的值是32768,也就是就会有32768个hashbucket。

一条hash chain上的bufferheader数量,没有固定限制(CR块有限制,一条hash chain上的CR块不能超过6个)。从隐含参数_db_block_max_cr_dba中可以查到这个限制:

NAME                                     VALUE      ISDEFAULT ISMOD      ISADJ

-------------------------------------------------- --------- ---------- -----

_db_block_max_cr_dba                     6          TRUE      FALSE     FALSE

判断是否有过长的hash chain的语句:过长的hash chain更容易引起热链进而引起CBC LATCH  

SYS@ prod>select * from(select hladdr,count(*) from x$bh group by hladdr order by 2 desc) whererownum<5;    ----------------x$bh.hladdr表示的是hash chainlatch address

HLADDR     COUNT(*)

-------- ----------

3E2A7088         26

3E27D788         25

3E2AABE8         24

3E2BD9C0         24

 

hash latch:就是latch:cache buffers chains --CBC LATCH

用于保护hash chain结构,一个CBC LATCH管理着多个hash chain

1.服务进程需要扫描hash chain上的bufferheader时或者叫要读取buffer cache中数据块,
2.服务器进程要将新读入的数据块挂载到hash chain上时

SYS@ prod>select count(*) fromv$latch_children where name like '%cache buffers chains%';

 COUNT(*)

----------

      1024

每个pool会有至少8个“Latch:cachebuffers lru chain”.

NAME                                     VALUE      ISDEFAULT ISMOD      ISADJ

-------------------------------------------------- --------- ---------- -----

_db_block_lru_latches                    8          TRUE      FALSE     FALSE

working set与lru latch一一对应。lru latch的数量是由一个隐藏参数:_db_block_lru_latches决定的。该参数缺省值为DBWR进程的数量×8。该参数最小必须为8,如果强行设置比8小的数值,oracle将忽略你设置的值,而使用8作为该参数值。

 

每个working set都具有它自己的一组LRU和LRUW链表(LRU和LRUW链表总是成对出现的)。
ORACLE为了提高buffer cache性能(大内存),使用了多个working set
每个working set都由一个名为“Latch:cache buffers lru chain”的latch来保护,每一个lru latch对应一个working set。
而每个被加载到buffer cache的buffer header都以轮询的方式挂到working set上去。也就是说,当buffer cache加载一个新的数据块时,其对应的buffer header会去找一个可用的lru latch,如果没有找到,则再找下一个lru latch,直到找到为止。如果轮询完所有的lru latch也没能找到可用的lru latch,该进程只有等待latch free等待事件,同时出现在v$session_wait中,并增加“latch misses”。
如果启用了多个DBWR后台进程的话,每个DBWR进程都会对应一个不同的working set,而且每个DBWR只会处理分配给它的working set,不会处理其他的working set。

SYS@ prod>select name fromv$latch_children where name like '%buffers lru%' and gets != 0;

NAME

----------------------------------------------------------------

cache buffers lru chain

cache buffers lru chain

cache buffers lru chain

cache buffers lru chain

cache buffers lru chain

cache buffers lru chain

cache buffers lru chain

cache buffers lru chain

8 rows selected。


SYS@ prod>selectd.blk_size,c.child#,p.bp_name,c.gets,c.sleeps from x$kcbwds d,v$latch_childrenc,x$kcbwbpd p where d.set_latch=c.addr and d.set_id between p.bp_lo_sid and p.bp_hi_sidorder by c.child#;

 BLK_SIZE     CHILD# BP_NAME                    GETS     SLEEPS

---------- ------------------------------ ---------- ----------

      8192          1 KEEP                         14          0

      8192          3 RECYCLE                      14          0

      8192          5 DEFAULT                   29310          0

      2048          7 DEFAULT                      14          0

      4096          9 DEFAULT                      14          0

      8192         11 DEFAULT                      14          0

     16384         13 DEFAULT                      14          0

     32768         15 DEFAULT                      14          0

8 rows selected.

总结:buffer cache中有pool,每个pool中至少有8个Latch:cachebuffers lru chain,每个Latch:cachebuffers lru chain对应着一个workingset,每个working set中,有多个CBC LATCH来,每个CBC LATCH管理着多个hash bucket,每个hash bucket对应着一条hash chain。
数据块在读入buffer cache中时,同时会在buffer cache中构造一个buffer header,ORACLE对数据块的DBA进行hash运算,根据运算结果将buffer header挂载到相应的hash chain上。
同时,每个working set中,有一对LRU和LRUW链表,buffer cache中的数据块,胜块会挂载到LRUW链表,其它块在LRU链表。也就是buffer cache中的数据块,肯定在LRU和LRUW链表之一:不能同时存在这两个链表上。


接--Buffer cache学习(三)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值