1 MySQL如何初始化Buffer Pool
Buffer Pool中有N多緩存頁,每個緩存頁還有個描述信息。DB啓動後,按BP大小向os申請一塊內存區域,作爲BP的內存區域。
當內存區域申請完後,DB按默認緩存頁及對應描述信息快,在BP中劃出一塊塊內存,當DB把BP劃分完後:
這時,BP中的一個個緩存頁還都是空的,要等DB運行起來後,當我們要對數據執行CRUD操作時,纔會把數據對應的頁從磁盤文件裏讀取出來,放入BP中的緩存頁。
哪些緩存頁空閒?
DB運行後,肯定執行大量CRUD,就需不停的從磁盤上讀取一個個數據頁放入BP中的對應的緩存頁裏去,把數據緩存起來,後續就能對該數據在內存裏執行CRUD。
但是此時在從磁盤上讀取數據頁放入Buffer Pool中的緩存頁的時候,必然涉及到一個問題,那就是哪些緩存頁是空閒的?
因爲默認情況下磁盤上的數據頁和緩存頁一一對應,都是16K,一個數據頁對應一個緩存頁。所以必須要知道BP中哪些緩存頁是空閒狀態。
所以數據庫會爲BP設計個free鏈表,雙向鏈表,每個節點就是個空閒緩存頁的描述數據塊的地址,即只要一個緩存頁空閒,那他的描述數據塊就會被放入free鏈表。
剛開始DB啓動時,可能所有緩存頁都空閒,因爲此時可能是個空DB,所以此時所有緩存頁的描述數據塊,都放入free鏈表。
上圖中,這free鏈表裏就是各個緩存頁的描述信息塊,只要緩存頁空閒,對應的描述信息塊就會加入free鏈表,每個節點都會雙向鏈接自己的前後節點,組成一個雙向鏈表。free鏈表有個基礎節點引用鏈表的頭節點和尾節點,存儲了鏈表中有多少個描述數據塊的節點,即有多少個空閒緩存頁。
free鏈表佔用內存大小
這free鏈表本就由BP裏的描述信息塊組成,可認爲是每個描述信息塊裏都有兩個指針:
-
free_pre
指向自己的上一個free鏈表節點
-
free_next
指向下一個free鏈表的節點
通過BP中的描述數據塊的free_pre和free_next兩個指針,就能將所有描述數據塊串成一個free鏈表,上面只是爲了方便畫圖,所以將描述信息塊單獨畫出來。
對free鏈表,只有一個基礎節點(40K)不屬於BP,存放了free鏈表的頭節點地址,尾節點地址,還有free鏈表當前節點個數。
如何將磁盤上的頁讀取到BP的緩存頁?
先從free鏈表獲取一個描述信息塊,就能獲取到對應空閒緩存頁。
就能將磁盤上的數據頁讀到對應緩存頁,同時將相關的描述信息寫入緩存頁的描述信息塊,比如該數據頁所屬的表空間之類的信息,最後把那描述信息塊從free鏈表中移除:
怎知數據頁是否被緩存?
執行CRUD時,先看該數據頁是否被緩存,若沒被緩存就走上面邏輯,從free找個空閒緩存頁,從磁盤上讀取數據頁寫入緩存頁,寫入描述信息,最後從free中移除該描述信息塊。
但若數據頁已被緩存,就能直接使用。
所以DB還有個數據頁緩存哈希表:
- key:表空間號+數據頁號
- value:緩存頁的地址
當要使用一個數據頁時,通過“表空間號+數據頁號”作爲K查這個哈希表:
- 若無,讀取數據頁
- 若有,說明數據頁已被緩存
每次讀取一個數據頁到緩存後,都會在這哈希表寫入一個數據,下次若再使用這數據頁,就能從哈希表直接讀出來,畢竟他經被放入一個緩存頁了: