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