« 《深入浅出Oracle》排行榜再进一步 | Blog首页 | 传华友世纪下周将精简部门并裁员30% »
关于新书中Dirty Buffer的问答
作者:eygle |【转载时请务必以超链接形式标明文章原始出处和作者信息及本声明】链接:http://www.eygle.com/archives/2006/08/dirty_buffer_question.html
今天有朋友在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:
| 相关文章 | 随机文章 |
|
|
2007年 新的开端 我的天使在成长 幸运的以及更幸运的 又是一年圣诞时 10gR2使用RMAN恢复临时表空间的增强 |
留言 (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
