《DBNotes: Buffer Pool对于缓冲页的链表式管理》
目錄
- Buffer Pool回顧
- Buffer Pool內(nèi)部組成
- freelist
- flushlist
- LRU鏈表管理以及改進(jìn)
Buffer Pool回顧
我們知道針對數(shù)據(jù)庫的增刪改刪操作都是在Buffer Pool中完成的,一條sql的執(zhí)行步驟可以認(rèn)為是這樣的:
1、innodb存儲引擎首先在緩沖池中查詢有沒有對應(yīng)的數(shù)據(jù),有就直接返回
2、如果不存在,則去磁盤進(jìn)行加載,并加入緩沖池
3、同時該記錄會被加上獨占鎖,防止多人修改,出現(xiàn)數(shù)據(jù)不一致
而且我們知道,可以通過設(shè)置my.cnf配置中的innodb_buffer_pool_size來修改緩沖池大小,加快sql查詢速度,當(dāng)然也需要注意設(shè)置過大會造成系統(tǒng)swap空間被占用,導(dǎo)致系統(tǒng)變慢降低查詢性能。
Buffer Pool內(nèi)部組成
緩沖池對應(yīng)一片連續(xù)內(nèi)存,我們將其劃分為大小為16kb的頁(與innodb對應(yīng)),這些頁稱為緩沖頁。
為了很好的管理這些頁,設(shè)計者為每個緩沖頁都創(chuàng)建了一些控制信息:表空間編號、頁號、緩沖頁在緩沖池中的地址、鏈表節(jié)點信息等。將每個頁對應(yīng)的控制信息占用的一塊內(nèi)存稱為一個控制塊。控制塊與緩沖頁一一對應(yīng),都存放在緩沖池中。
在Mysql啟動時,會自己完成對緩沖池的初始化:向操作系統(tǒng)申請內(nèi)存,自己劃分成若干對控制塊和緩沖頁。
freelist
當(dāng)我們從磁盤中l(wèi)oad一個數(shù)據(jù)頁到緩沖池中,我們應(yīng)該放到哪個緩沖頁中呢?
很顯然我們應(yīng)該把數(shù)據(jù)頁放到“空閑”的緩沖頁中。
設(shè)計者將所有空閑的緩沖頁對應(yīng)的控制塊作為一個節(jié)點放到一個鏈表中,稱為freelist。每次從freelist中取出一個空閑的緩沖頁中,并且將該緩沖頁對應(yīng)的控制塊信息填上,然后將該節(jié)點移除,表示緩沖頁已經(jīng)被使用了
flushlist
當(dāng)一個控制塊節(jié)點被從freelist中移除,說明該頁已經(jīng)被使用了。如果這種“使用操作”是對數(shù)據(jù)進(jìn)行修改的話,那么必定需要將該頁數(shù)據(jù)flush到磁盤上。但是每次修改一頁就將那一頁flush的話,磁盤IO占用率高。所以每次修改緩沖頁后,將這些臟頁控制塊放入一個fulshlist上。當(dāng)flush時機到了,就把flushlist節(jié)點對應(yīng)的緩沖頁刷新搭配磁盤上。
LRU鏈表管理以及改進(jìn)
緩沖池內(nèi)存有限,當(dāng)freelist中沒有多余的空閑緩沖頁,就需要把某些舊的緩沖頁從緩沖池中移除,然后把新的數(shù)據(jù)頁放進(jìn)來。為了提高內(nèi)存命中率,使用LRU。
但是普通的LRU不能解決下面的問題;
1、加載到緩沖池的頁不一定被用到(針對于預(yù)讀)
2、如果有非常多的使用頻率低的頁被同時加載到緩沖池中,則可能會把那些使用頻率非常高的頁從緩沖池中淘汰。(針對全表掃描)
關(guān)于innodb對于LRU的改進(jìn)見如鏈接:
MySQL——Innodb改進(jìn)LRU算法
當(dāng)然還有進(jìn)一步的優(yōu)化:
對于young區(qū)域的緩沖頁,每次訪問一個緩沖頁就要把它移動到LRU鏈表的頭部,開銷比較大。畢竟,young區(qū)域的緩沖頁都是熱點數(shù)據(jù)。所以我們可以這樣優(yōu)化:只有被訪問的緩沖頁位于young區(qū)域1/4的后面時,才會被移動到LRU鏈表頭部。也就是說我們將young的前0.25部分稱為very young,very young里面的數(shù)據(jù)訪問不會移動到頭部,因為大家訪問頻率都是非常高的。
提醒一下,在LRUlist的節(jié)點不是freelist節(jié)點,可能是flushlist節(jié)點。不理解的話,再去上面看看兩個list定義。
然而這一切的目的只有一個:盡量高效地提高緩沖池命中率。
總結(jié)
以上是生活随笔為你收集整理的《DBNotes: Buffer Pool对于缓冲页的链表式管理》的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。