eygle.com   eygle.com
eygle.com  
 

« 《深入浅出Oracle》排行榜再进一步 | Blog首页 | 传华友世纪下周将精简部门并裁员30% »

关于新书中Dirty Buffer的问答

作者:eygle |【转载时请务必以超链接形式标明文章和作者信息及本声明
链接:
今天有朋友在ITPUB上提问,问到新书中提及的一个说法:
P165页:一个buffer要么在LRU上要么在Dirty list,不能同时在多个list上。

问题是这样的:
如果一个block被移到Dirty list(=checkpoint queue?),Oracle怎么判断这个block到底是hot还是cold?

这个问题我是这样回答的:
所有Dirty Buffer,首先要被移动到Dirty List上去,然后从Dirty List上被写出。

一旦Buffer变得Dirty,在被写出之前都不能被重用。

也就是不存在Hot/Cold之说了。
Hot/Cold是针对LRU List,并非Dirty List。

Biti也就此问题作出了回答,具体可以参考ITPUB的链接。

By eygle on 2006-08-15 22:00 | Comments (11) | Posted to FAQ | Edit |Pageviews:

相关文章 随机文章
  • Oracle Patch Set Note And Bug List 参考
  • Oracle 9i 的生命周期支持策略
  • 各取所需:Oracle收购BEA,SUN收购MySQL
  • Oracle还是IBM的中文推广力度大?
  • Oracle与Linux/Unix下的时间处理
  • 2007年 新的开端
    我的天使在成长
    幸运的以及更幸运的
    又是一年圣诞时
    10gR2使用RMAN恢复临时表空间的增强
    网上相关主题:
    Google

    留言 (11)

    确切的说,当data buffer被移到lruw(注意是lruw而不是ckpt queue)后它的touch count将被清0,它将被添加到lruw的tail,而dbwr写出dirty buffer将从lruw的head开始(当然当checkpoint发生dbwr安装ckpt queue的顺序写出,lruw和ckpt queue分别针对不同的情况写出,ckpt queue负责checkpoint时候的写出顺序,而lruw负责其他dbwr写条件发生时写出的顺序,两者在dirty buffer write out时都起作用),当buffer存在lruw时,它的touch count是不起作用的,当它还没被write out时又被某个进程访问,那么它将被放入AUXILIARY lru list,同时它的touch count将重新开始起作用。

    下面是一个例子

    更新一个表,并设法使它的block buffer进入lruw
    注意第一个地址0x21ff50ac,在这时候它在lruw,并且tch为0
    MAIN WRT_LST Queue header (PREV_DIRECTION)[227e6320,21ff5100]
    0x21ff50ac=>0x20ff23fc=>0x20feae6c=>0x20ff439c=>0x217eb3ec=>0x21bfab6c=>0x20ff03ac=>0x20fea4cc

    CHAIN: 473 LOC: 0x27d510a8 HEAD: [21ff50ac,21ff50ac]
    BH (0x21ff50ac) file#: 4 rdba: 0x0100f7c7 (4/63431) class: 1 ba: 0x21ebc000
    set: 3 blksize: 8192 bsi: 0 set-flg: 0 pwbcnt: 0
    dbwrid: 0 obj: 80582 objn: 80582 tsn: 4 afn: 4
    hash: [27d510a8,27d510a8] lru: [20ff2450,21fee250]
    lru-flags:
    ckptq: [217f2584,20feae94] fileq: [217f258c,20feae9c] objq: [20ff24a4,223f73b4]
    st: XCURRENT md: NULL tch: 0
    flags: buffer_dirty only_sequential_access redo_since_read
    LRBA: [0x218.1cd5.0] HSCN: [0x5.e85ddeec] HSUB: [1]
    buffer tsn: 4 rdba: 0x0100f7c7 (4/63431)
    scn: 0x0005.e85ddeec seq: 0x01 flg: 0x00 tail: 0xdeec0601
    frmt: 0x02 chkval: 0x0000 type: 0x06=trans data
    Hex dump of block: st=0, typ_found=1


    再次访问这个block

    update test set object_id=object_id+1 where rowid=DBMS_ROWID.ROWID_CREATE(1,80582,4,63431,0);
    update test set object_id=object_id+1 where rowid=DBMS_ROWID.ROWID_CREATE(1,80582,4,63431,0);
    ......
    update test set object_id=object_id+1 where rowid=DBMS_ROWID.ROWID_CREATE(1,80582,4,63431,0);

    它被移回AUXILIARY LRU LIST,并且tch开始重新计算

    AUXILIARY RPL_LST Queue header (NEXT_DIRECTION)[20bf5260,20fee0f0]
    ......
    0x21ffb3ac=>0x21fe679c=>0x21bf838c=>0x20bf6b7c=>0x20ffaccc=>0x20fec1ac=>0x21fee1fc=>0x21ff50ac(这个地址)
    ......
    CHAIN: 473 LOC: 0x27d510a8 HEAD: [21ff50ac,21ff50ac]
    BH (0x21ff50ac) file#: 4 rdba: 0x0100f7c7 (4/63431) class: 1 ba: 0x21ebc000
    set: 3 blksize: 8192 bsi: 0 set-flg: 0 pwbcnt: 0
    dbwrid: 0 obj: 80582 objn: 80582 tsn: 4 afn: 4
    hash: [27d510a8,27d510a8] lru: [20ff2450,21fee250]
    lru-flags: on_auxiliary_list
    ckptq: [27dae774,223e8554] fileq: [27dae7c4,27dae7c4] objq: [2544db18,2544db18]
    st: XCURRENT md: NULL tch: 5
    flags: buffer_dirty gotten_in_current_mode block_written_once
    redo_since_read
    LRBA: [0x218.2862.0] HSCN: [0x5.e85de53c] HSUB: [2]
    buffer tsn: 4 rdba: 0x0100f7c7 (4/63431)
    scn: 0x0005.e85de53c seq: 0x01 flg: 0x00 tail: 0xe53c0601
    frmt: 0x02 chkval: 0x0000 type: 0x06=trans data

    Posted by: wanghai at August 16, 2006 2:32 PM

    你这个例子构造的比较特殊,其实就相当于一个session对一个Buffer进行了多次修改。

    Posted by: eygle at August 16, 2006 3:55 PM

    例子没写全,开始更新test表导致buffer进lruw是在其他session做的,进lruw后然后再开其他session再次访问这个buffer。

    Posted by: wanghai at August 16, 2006 3:59 PM

    The LRU-W (write) list is used to hold buffers that aged out of the LRU but need to be written to disk before they can be reused.

    这里说的不能重用是针对buffer被write to disk后变成free buffer来说的,在被写出磁盘前这个buffer是不能被覆盖的,不是指的是它不能被移回lru并被其他 session修改。

    Posted by: wanghai at August 16, 2006 4:06 PM

    最后这个解释是全面的:D

    Reuse是指被别的数据使用,对于当前Block是可以被继续pin或修改的。

    Posted by: eygle at August 16, 2006 4:11 PM

    对于你的这个测试,其实数据库就是省略了一个写回Disk,再从Disk读出来的过程。

    直接在Buffer内,从lru-w到lru倒了一下手而已。

    :)

    Posted by: eygle at August 16, 2006 4:14 PM

    因为lruw和lru无非是双向链表,保存的无非是buffer address,操作非常迅速,比发生io代价小得多,所以oracle还是实现的聪明的,呵呵

    Posted by: wanghai at August 16, 2006 4:18 PM

    这个还是容易理解的,不过关于细节以前的确没有想得这么清楚。

    谢谢wanghai同学:)

    Posted by: eygle at August 16, 2006 4:26 PM

    如今这么认真的人不多了 :)

    Posted by: biti_rainy at August 16, 2006 10:29 PM

    我也给一个物理上的解释:是以前写的东西的一部分

    基础的概念:
    Hash buckets是一个结构,维护这数据缓存头的列表,是有相关的dba和类号来分类;
    Hash chain是在一个hash bucket上的一个数据缓存头的列表。
    LRU:是一种机制,用于确定在搜索空闲的缓存的时候,哪一个缓存能够被使用。


    缺省的hash bucket数目是:DB_BLOCK_BUFFERS*2
    通过设置参数_DB_BLOCK_HASH_BUCKETS能够重写hash bucket数目
    每一个HASH BUCKET包含这一个缓存头的一个链,
    每一个hash bucket有一个cache buffers chains latch来保护对这个链的同步访问。

    这几个概念说这相对比较复杂,解释一下,这里还有一个缓存内存区域,这个是存放数据的物理位置,在上面有几个结构:
    Hash bucket
    Buffer header

    其中Hash bucket的数目是通过参数设置的,之所以使用这个概念,主要是才查找缓存的数据的时候能够更快找到所需要的数据的地址。而在Hash bucket这个结构中有一个链,这个链是有Buffer header组成,在Buffer header这个结构上有指向存放数据具体位置的指针地址。在查找数据的时候,数据库通过hash算法确定是有哪一个Hash bucket来存放所需要的Buffer header,在通过Buffer header上的buffer address来确定具体数据存放的位置。

    还有两个链,LRU和LRUW,这两个链也是通过Buffer header上的LRU chain的指针来实现的,每一个Buffer header只有一个LRU chain指针,这也就是为什么同一个块不能同时存放在LRU和LRUW的原因了。

    在这里我们可以看到,这里组成了一个二维的一个网状的一个链网,这个联网相互交叉,在LRU和LRUW其实只是一个虚拟的一个链,是有Buffer header来实现,Hash bucket目的是实现数据地址的快速查找,但是LRU和LRUW是找到相应的各自的功能,Oracle就是通过这样的设计来实现一种物理结构实现两种不同的功能。

    Posted by: littterbaby at August 23, 2006 7:52 AM

    楼上的兄弟,写的真是详细,我最近也在研究这个缓存机制,希望能与你交流。能不能把你以前写的这个完整文章发给我一份呢,谢谢您了。我的信箱是ximengzhan@etang.com

    Posted by: ximengzhan at September 1, 2006 5:08 PM

    发表留言:



    Remember Me?
    (输入验证码后方可评论,谢谢支持)



    CopyRight © 2004 eygle.com, All rights reserved.