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日
    文字:韻箏

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章