oracle学习笔记 buffer_cache内存组织结构剖析



oracle学习笔记  buffer_cache内存组织结构剖析


这节课讲buffercache内存组织结构
讲到的概念有:
CBC
LRU
LRU里面又分LRU、MRU
LRUW
CHECKPOINT QUEUE检查点队列


一)buffercache内存组织结构


关于内存组织结构
在sharedpool里面讲过了
使用chain(链)管理
链下挂了很多内存块


内存中有多个链50个100个200个
根据sharedpool大小的不一样
oracle会自动去分配相关的链
然后把相关的内存块以某种规律挂到链上
我们要找某一个内存块的时候
先确认内存块应该在哪个链上
因为链的特点是串起来
既然串起来就是中间没有断的地方
就可以在链上找到链的头部
然后一个内存块的一个内存块的去遍历
可以一直把链遍历完
所以sharedpool里面内存块的特点是chain链


buffercache里面的内存结构也一样也是链


举例:
一排有三个同学
一共三排
就是三排三列的结构
比如想把第一列的同学链起来
在物理上实现
可以用根绳子绑住第一个再绑住第二个再绑住第三个
这样拿着绳子的头部
顺着绳子可以
先找到第一个再找到第二个再找到第三个
这就是传统意义上的链和遍历


在内存里面没有绳子绑
假如刚才的三个同学
我在第一个同学的后背上贴上一个地址
这个地址指向后面的同学
在第二个同学的身上
在前胸上贴上一个地址指向第一个前面的同学
在后背上贴上一个地址指向后面的同学
在最后一个同学的前胸上贴个地址指向第二个同学
这样我们并没有物理上用绳子把三个同学链起来
在每个块的前胸后背上分别贴上了前面同学和后面同学的地址
这时找到第一个同学以后
按地址可以找到第二个也可以找到第三个
第三个反过来可以找到第二个
第二个可以找到第一个


这就是我们内存里面所谓的链
chain链是一种结构一种组织方式
就是在每个块上写上前面和后面的地址
我们这个链叫双向链
向前可以走往后也可以走
因为在每个人身上贴俩地址
也可以单向链
单向链只有在后背上写地址只有往后面找
oracle里面一般都是双向链


oracle里面实现链就是在每个内存块里写上不同的内存地址


现在链了第一列的三个同学
根据的是它们的地理位置
也可以第二列的三个同学链起来
第三列的三个同学链起来
将来找的时候
我要找第一列的直接找就可以了
这个链的作用就是将物理上有规律的一些块(人)给链起来


不同的链有不同的意义


现在我想把男同学给链成一个链女同学链成一个链


比如第一排第一个同学a第二个同学b为女性
第二排第三个同学c为女性
第三排第二个同学d为女性

在a身上贴上b的地址
在b身上贴上a、c同学的地址
在c同学身上贴上b、d同学的地址
d身上贴上c同学的地址
这样也可以是一个链


当然男同学也可以链起来
这种链是按照人的性别去链的


要找女同学的时候找到上面的女同学链
找到第一个就会找到第二个第三个再找到第四个


不同的链不同的作用


在这九个人组成的结构体中可以同时有多种链
按地理位置链成三个链
将来按地理位置找时可以使用位置链去找
这时结构体中还有另外一种性别链
可以把所有的女生找出来
找时找到女生链按它的链走


也就是一个结构体中可以有多个链
每种链有每种链的作用
这么多链实现很简单就是在人身上贴地址就行
在人身上贴两个地址形成一个双向链
在人身上贴四个地址就属于两个双向链
贴六个地址它就可以属于三个双向链


oracle数据库里面内存组织结构都是通过链的方式
因为我们有很多内存所以需要组织结构


oracle内存结构中
有buffercache
其中有一堆内存
对所有内存来讲将来有很多需要找内存的情况
比如讲有十万个内存块
要从这么多内存块找内存块的时候
如果你不给它组织起来会非常麻烦简直不可用


第一确认内存块确实需要组织起来
不组织起来使用内存块的时候非常麻烦


第二内存块找的时候有各种各样找的方式
比如找那些脏块是种找的方式
因为DBWn需要把脏块找出来写到磁盘上
根据某个地址找也是一种方式
当然还有别的方式


比如这里内存块里面我要找干净的
干净意味着可用
第一找干净的块
第二找干净里面最近一段时间几乎没有被访问过的块
最近多少时间这个块没有被访问过就可以把这个块给扔掉了
然后从磁盘里面把别的block块调到这个buffer里面去
实际中有这个需求


所以说我们现在明白几个概念
buffercache这些块需要组织
需要组织我们就用链
我们知道不同的链有不同的意义
所以说我们看buffercache里面应该有多种链把内存块组织起来


二)CBC链


buffercache中第一种链CBC链
CBC:cache buffer chain


内存有buffercache,磁盘有dbf


在buffercache整个的占用内存中
buffercache里提前建了很多链,链是空的
内存另外一部分是已经被划分好的一个一个的块叫buffer
在dbf文件里面的块是block


这时oracle发出一个sql语句
要访问某个表的某个行
oracle经过计算以后发现
这个表的这个行在dbf的某个块里面
这时oracle把这个块调到内存里面去


如语句
select * from t2 where id=1;
要访问表t2中id=1的那个行
这时oracle经过计算以后发现这个行所在的块
块的地址是1号文件的第24个块
block块的地址有了


首先oracle做的第一个事情
根据块地址发现这个块应该在内存buffercache中的第二个链上
然后开始找,对第二个链进行遍历
发现第二个链是空的
或者2号链上有一些buffer但是没有我们需要的buffer
这时就会发生物理IO
在内存里面找到一个空闲buffer块
把dbf文件对应的块调到内存中写到这个buffer里面去


当写进去的时候oracle同时也会
把block块的头部拿出来挂到第二个链上
头部主要记的块的地址和块的类型这里是表类型
然后在块的头部新形成一个地址
直接指向buffercache中的那个同时写入的buffer块的地址


buffer cache中所有的chain连接的都是buffer header,而不是buffer本身
链通过在buffer header里保存指向前一个buffer header的指针和指向后一个buffer header的指针的方式实现
buffer header是buffer的头部,
主要保存指向buffer的指针既buffer实际的内存地址、一些关于该buffer header所在链的信息等
每一个block数据块在被读入buffer cache时,
都会先在buffer cache中构造一个buffer header,buffer header与数据块一一对应。


oracle第二次读的时候
select * from t2 where id=2;
读第二行的时候oracle经过计算后发现
要访问t2的第二行id=2的哪一行
发现这个块的地址是1号文件24号块
进过计算发现这个块应该在二号链上
它就找到二号链
对二号链所有的buffer header进行对比进行计算
发现有个buffer header它的块的地址和我们要找的块的地址是一样的
就根据这个buffer header找到这个buffer
然后从buffer里面找数据


oracle的buffer cache里面有一堆链
链的序号是按照block块的地址计算得到
每个链上挂的都是对block块地址进行计算得到值相同的块的头部
在链上挂上去的头部有对应block的地址
在进入内存时记录下了这个块对应在内存中的buffer的地址
而且加入链时
此头部会记下所在链的上一个和后一个的链成员(块头部)的地址这样就形成一个链组成单元
这堆链将整个的buffercache所有的数据块给链起来
将来根据block块地址要找buffer的时候找链就可以
这是根据地址将整个buffercache给链起来


将来oracle能够做到
你要访问某个表里面的某一行和某多行
oracle能够计算出你要访问的这些行在oracle的哪些块里面
能够计算出你要访问的block块的地址
而我们知道CBC链将buffercache里面所有的块按照块地址(在dbf中的地址)给链起来了
所以说我们就可以找到相应的链以后在链上去找
看看我们找的块在内存里有没有对应的buffer
没有的话发生物理io挂到这个链上


CBC链就是
以在dbf中block块地址的方式将buffercache里面所有的buffer链起来
它的作用是根据block地址找block的时候需要使用到,这时要跳转到CBC chain


三)LRU链


再看第二个链LRU链
LRU:least recent use最近最少使用


oracle实例有buffercache和dbf


我们要读某个块的时候
先到内存找,如果没有,我们来读dbf,
然后需要将dbf里面的block写到内存,就要找一个buffer


内存buffer的状态有几种
1、free从来没被使用过
2、clean干净的
   这个buffer对应一个block,俩内容完全一样是干净的
3、dirty脏的
   这个buffer对应着block
   但是这个buffer在内存里被修改了还没有写回到dbf中
   dbf中是旧数据,buffer中是新数据
   我们就认为这个buffer是脏的需要写回dbf,写回以后修改数据才能得到保存


找buffer时
有free buffer直接用就可以了因为里面什么都没有


如果有clean buffer也可以用
因为假设一开始此buffer和一个block对应两个的数据完全一样
把这个buffer数据覆盖掉,把新的block调到这个buffer使它和新的block对应也没有关系
因为磁盘还有一份和此buffer原来内容一样的block


有free最好,没有free有clean也可以


但是dirty不能被覆盖因为会造成和原对应block两个数据不一致
用新block覆盖掉会发生数据丢失


oracle数据库运行一段时间以后free非常少了几乎没有
几乎全部是clean


但是clean的有不同的使用情况
如有三个clean干净块
有一个经常被使用说明块的命中率很高
这时有一个第三个块几乎不被使用,特别是最近一段时间它几乎没有被用过
这三个块我们覆盖时应该先覆盖第三个块


oracle怎么知道到底该覆盖谁呢
可以这样,比如:buffercache有九个块
oracle根据地址已经串成了三个链是CBC链
同时有4个干净块
oracle根据最近最少使用原则将这四个块再串起来
其它5个块是脏的先不串它只串干净的
有一个最近最少被使用只使用了一次
其它三个干净块被分别使用2次3次4次
那么把它们串成LRU链
使用了1次的链在最前面然后再链上使用了2次的3次的4次的
被使用一次的叫冷端
使用次数多的叫热端


其实LRU上会链几种块
free的块和clean的块都有
暂时先认为LRU上链的是干净块


当我要找可用块的时候就找LRU这个链
先使用这个链的冷端,就是L端


热端是most端、M端
LRU是least recent used最近最少使用
MRU是most recent used最近最常使用
一个冷端一个热端


我们在LRU上找可用的块
从冷端找到一个buffer把它覆盖
这时对数据库的影响最小


这就是LRU
包括LRU MRU


四)LRUW链


LRUW:Least Recently Used Write
也叫做dirty list,也就是脏数据块链表


某个buffer header要么挂在LRU上,要么挂在LRUW上,不能同时挂在这两个链表上


LRUW上链的是脏块
把脏块串起来
因为我们知道oracle有个进程叫DBWn
它会周期性启动把脏块写到磁盘
DBWn要知道哪些块是脏的


上述例子中
9块buffer中有5块是脏的
如果你把五块串起来的话
DBWn就可以根据这个链找到脏块


假设
有一个块不但是脏的而且经常被使用经常被访问
如果把这个buffer块写到磁盘,此块变为干净状态
因为原block经常被使用
如果这时此buffer没有被其它block覆盖它也有可能马上又脏了
如果原buffer被其它block覆盖
这时会出现可能马上原block块马上又有一个对应的脏buffer


但是有其它一个块
它虽然是脏的但是最近很少被使用
如果把这个块写到磁盘的话,写到磁盘就干净了
干净的话就放到LRU上了
放到LRU上意味着它可以被覆盖了
这样挺好


但对第一个脏块来说
它脏不说而且最近经常被访问
如果我把它写到磁盘了把buffer挂到LRU上
原block可能马上又被修改了
它可能马上又脏了
或又生成一个对应的脏buffer被挂回到LRUW上了


这个时候
DBWn写的时候应该优先写这个脏的而且最近不怎么被经常访问的
所以说对脏块来讲
我们串的时候我们不但要串起来
也要按照最近最少脏最近最少被修改这个顺序被串起来
这样的话
我们DBWn写的时候才最有意义


也就是DBWn可以把
最近最少使用的脏buffer写到磁盘上了
然后挂到LRU上了


第一它被覆盖影响不大
第二因为它最近最少很少被访问
所以可以长时间在LRU上呆着


LRUW是为DBWn用的
LRU是我需要将磁盘的block调到内存的时候找空块可用块的时候找LRU
CBC根据block块地址找buffer的时候用
三个链有三个不同的作用


五)CKPTQ链


CKPTQ:CHECKPOINT QUEUE检查点队列

它也是将脏块链起来


LRUW将脏块链起来它是按照脏块被脏的频率去链的
检查点队列链的时候链的顺序不一样
它按照这个块第一次脏的时间点链起来


假设3*3矩阵中
有三个脏块
有一个脏块第一次被脏的时候是12:01分
有一个被脏的时候是12:02分
另一个被脏的时候是12:03分
check point队列按第一次被脏的时间点给它链起来


12:04分的时候12:01分被脏的块又被脏了一次
这时候这个块也不会挂在12:03分脏块的后面
因为check point队列是
1、脏块
2、是按照脏块第一次被脏的时间点链起来的



这节我们从理论上讲了buffercache内存组织结构
回顾:
首先
buffercache里面的buffer大小都一样
不像是sharedpool中chunk大小不一样
第二
buffercache中专门有一个内存结构链
链指向buffer



2016年9月25日
    文字:韵筝

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值