Oracle Dababase_buffer_cache数据库高速缓存组织结构剖析

这篇文章是参考甲骨论老相老师的教学视频:
http://v.youku.com/v_show/id_XMzkyMjA0NDQ0.html
所做的学习笔记


其实之前已经介绍过shared pool的链式(chain)内存结构了..
http://nvd11.blog.163.com/blog/static/200018312201301875752730/

1.双向链表
其实在Database buffer cache中, 也是用类似的chain结构, 只不过oracle一般是用双向链表.

所谓单向链表,  就是指每个内存块(chunk)有1个尾部指针指向1个chunk的头部地址. 除了最后1个chunk,尾部是空指针.
它只能单向从头1个chunk开始单向遍历.

而双向链表则是每个chunk中前面多了个指针去指向前1个chunk的头部地址,如下图:
双向链表的特点很明显, 就是可以双向遍历啦.

Oracle Dababase_buffer_cache数据库高速缓存组织结构剖析 - 饥民 - 饥民2011


2.多链交叉
       Oracle在database buffer cache中存在多链交叉, 也就是说1个chunk可以同时存在于多条双向链中.
       实现原理也很简单, 只不过在chunk头部和尾部再加若干个指针指向不同链中的下1个chunk(图就不画了.,,)


3.Oracle必须把database buffer cache的内存块组织起来.
       相当于1个buffer来讲, database buffer cache显得十分巨大, 单独查找1个buffer就十分困难了, 所以有必要将各个buffer组织起来.
       而查找某个buffer有多种方式:
       1.例如我要找的是若干个脏块, DBwr进程会把它们写入dbf, 所以会存在一条专门连接脏块的chain.
       2. 例如我要找1个干净的,而且最近访问次数很少的, 就把它移出缓存,让别的buffer使用, 所以会存在1条干净块的链..
       ....
      
4.所以Oracle会在database buffer cache中存在很多条交叉的双向内存链.
        
下面会介绍几条主要的链

5. CBC(cache buffers chain)
         CBC是database buffer cache中一种很重要的链, 作用类似于shared pool的chain, 用于给Server Process查找需要的数据缓存.
          具体流程可以参考下图:
Oracle Dababase_buffer_cache数据库高速缓存组织结构剖析 - 饥民 - 饥民2011
 

如上图,
可以逻辑上,将database buffer cache分成两部分, 1部分存放很多条CBC chain, 另1个就是存放buffer 区.



1. Server Process根据执行计划, 算出了要提取的数据在某个dbf文件的某个block中,   例如1号 dbf 文件24号block.
2 . Server process 会根据这个block编号算出对应buffer的头部信息在那个 chain中.
3, 在对应chain查找对应的头部信息,
4. 找不到的话, 就会去dbf文件中把对应block分成两部分, 头部信息被挂到CBC 链(buffer header,包含对应buffer的地址类型等信息),  row data部分被写入1其中1个空buffer中. 并修改头部信息, 增加1个指针指向那个写入row data的buffer中(物理读)
 5. server process根据CBC chain中的头部信息指针, 找到对应buffer, 提取数据给用户.

可以理解出, 当这个block以前未被访问过时, oracle必须执行1-5步,其中包括第4步物理读,  下次访问时就只执行1 2 3 5步,只需逻辑读了.

所以CBC链是将很多个buffer 的buffer header串联起来的一条内存链,  用于server process 根据block地址找到缓存中对应的buffer.


6. LRU(Least recent used) chain
    LRU链, 看名字也可以大概知道, 这时一条用于查找最近最少使用的buffer的链.
    而事实上,在这条链挂着的都是干净的buffer, 那么什么情况下oracle要查找最少使用的干净buffer呢?

    答案也很简单, 就是上面那副图,
    第4步:找不到的话, 就会去dbf文件中把对应block分成两部分, 头部信息被挂到CBC 链(buffer header,包含对应buffer的地址类型等信息),  row data部分被写入1其中1个空buffer中. 并修改头部信息, 增加1个指针指向那个写入row data的buffer中(物理读)

   注意高亮的空buffer就是指free buffer, oracle会优先将数据文件的block数据缓存在这些free 的 buffer中, 因为这些buffer没有数据时空的嘛.

     但是当数据库稳定运行一段时间之后,  database buffer cache里面就几乎没有空的buffer了, 都是有数据占用的buffer,

     前面几篇文章都提到过,  这些有数据的buffer 分两种, 一种是干净的, 一种是脏的.   而脏的数据是指还未被DBWR进程写入数据文件,是不可以用的, 详细请看这里:
http://nvd11.blog.163.com/blog/static/200018312201301592518115/

      所以Oracle只能把干净的buffer挑出1个,然后让新的block数据写到这个buffer中.  但是因为原来干净的buffer数据被覆盖.所以下次访问这个buffer的数据就要重新进行1次物理读了.

      所以Oracle就要根据最近访问次数排序,从而选出最近访问最少的那些干净buffer, 作为新的可用空间.

      所以database buffer cache会存在一种内存链, 这条链会根据最近访问次数将干净buffer按次数多少连接起来, 这条链就是LRC链了.

     lRC链与其他chain一样,都有头部和尾部,  头部就是最近访问次数最少的buffer,叫做冷端(cold end),  反之尾部就叫热端(most end). 而oracle会不断维护这条LRC链(如根据访问次数调整顺序),当需要替换干净buffer时, 就会从冷端开始找啦.

7. LRUW(Least recent used WRITED) chain
    与上面那条LRC chain对应, 有一条专门for  脏buffer的链, 而且是按最近修改次数排序的.
   
     那什么时候需要者条链呢, 事实上, Oracle有条DBWR 后台进程, 专门负责将database buffer cache里的脏数据写回dbf, 一旦写回,这个脏的buffer就变成干净的了.  这个动作时很费时间的,因为这是1个物理写动作.

       但是如果1个脏buffer最近修改次数很多, DBWR就算写回dbf, 很可能不久后又一次修改(就是又脏了), 所以DBWR会优先将那些最近修改次数最少的脏buffer 写回dbf, 可以避免多余的物理写(物理IO)啊~

      而LRUW链就是为DBWR找到最近最少修改的脏buffer服务的. 不难理解.

8. Check Point Queue (检查点队列) chain
     这条链式按照第一次被修改的时间排序的脏buffer链.

     注意2点:
     1, 里面都是脏buffer
      2. 按照第一次被修改(变脏)时间排序
                 也就说有3个buffer   假如它们第一次修改时间分别是  12:00 13:00 14:00, 那么它们就按照这个顺序排序了, 假如15:00 时第1个buffer又被修改了,  但是这时它们的顺序不会变, 因为顺序依据是第一次的被修改时间啊~

     这条链有什么作用呢,  视频里老相老师没有说,他说以后再讲, 我也以后再补充吧...
posted @ 2013-04-02 00:57  Gateman  阅读(516)  评论(0编辑  收藏  举报