eygle.com   eygle.com
eygle.com  
 

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

关于新书中Dirty Buffer的问答

今天有朋友在ITPUB上提问,问到新书中提及的一个说法:
P165页:一个buffer要么在LRU上要么在Dirty list,不能同时在多个list上。

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

这个问题我是这样回答的:
所有Dirty Buffer,首先要被移动到Dirty List上去,然后从Dirty List上被写出。在移动到Dirty List之后,原有的计数被取消。也就是不存在Hot/Cold之说了,Hot/Cold是针对LRU List,并非Dirty List。

实际上,在内存中,可以反复对一个数据块进行多次修改,这可以变现在,在一个会话内多次修改一条记录,或者在某个会话提交之后,被其他会话再次修改。

但是这些修改会导致数据块在不同链表上的迁移,
如果一个数据块变得Dirty,它会在检查点队列上注册,也可能被移动到Dirty List上,如果在写出之前再次修改,那这个数据块可以被迁移出dirty list,继续被再次修改,但是数据块在Checkpoint Queue上的顺序不会改变,这是Oracle 8版本引入的变化,也正是由于checkpoint queue来确保写出的顺序才得以实现了增量检查点。


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

历史上的今天...
      >> 2007-08-15文章:
      >> 2005-08-15文章:
             孟静其人
------
这篇 【关于新书中Dirty Buffer的问答】来自 eygle.com | CSDN网摘| del.icio.us|Google订阅 | 鲜果订阅 | 抓虾订阅

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

相关文章 随机文章
11gR2新特性之二 - Flash Cache 的SSD支持
如何在自动SGA管理模式下调节参数设置
20090811-墨墨、书书、Oracle
Oracle收购GoldenGate - 甲骨文到底想做什么
Granule 与 Redo Log Buffer (log_buffer) 的关系
在Oracle10gR2中调整过于频繁user commit的一个方法
Install MT WYSIWYG plugin FCKeditor
温总理做客新华网、政府网与网友在线交流
ORA-600 17285 错误 与 PL/SQL Developer
RAC相关的一则DBA招聘需求
搜索本站:

留言 (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~2010 eygle.com, All rights reserved.