您的位置:首页 > 数据库 > Oracle

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

2016-09-25 17:15 337 查看


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日

文字:韵筝
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: