深入理解MySQL——LRU、Free和Flush 链表
首先,緩沖池申請的內(nèi)存空間一定是頁大小(默認(rèn)16KB)的倍數(shù),換句話說,雖然緩沖池是一塊很大的內(nèi)存區(qū)域,然而在使用時(shí)是根據(jù)固定的頁大小進(jìn)行管理的。如圖1-1所示∶
緩沖池有一個(gè) free 鏈表,其中保存著未被使用的內(nèi)存頁空間。當(dāng) free 鏈表中的頁都已分配完畢,當(dāng)再要申請空間時(shí),則需要根據(jù)LRU(Latest Recent Used 最近最少使用)算法淘汰已經(jīng)使用的頁。
通常來說,數(shù)據(jù)庫中的緩沖池都是通過 LRU(Latest Recent Used 最近最少使用)算法來進(jìn)行管理的。即最頻繁使用的頁在 LRU鏈表的前端,而最少使用的頁在 LRU鏈表的尾端。當(dāng)緩沖池不能存放新讀取到的頁時(shí),將首先從LRU 鏈表中釋放尾端的頁。
在InnoDB存儲(chǔ)引擎中,其同樣使用 LRU 算法對(duì)緩沖池進(jìn)行管理。稍有不同的是 InnoDB存儲(chǔ)引擎對(duì)傳統(tǒng)的LRU算法做了一些優(yōu)化。在InnoDB的存儲(chǔ)引擎中,LRU鏈表中還加入了midpoint 位置,新讀取到的頁,雖然是最新訪問的頁,但并不是直接放入到LRU 鏈表的首部,而是放入到LRU鏈表的 midpoint 位置。這個(gè)算法在 InnoDB存儲(chǔ)引擎下稱為 midpoint insertion strategy。默認(rèn)配置下,該位置在 LRU鏈表長度的 3/8處,如圖1-2所示。
那為什么不采用樸素的 LRU 算法,直接將讀取的頁放入到LRU鏈表的首部呢?這是因?yàn)槿糁苯訉⒆x取到的頁放入到LRU的首部,那么某些 SOL 操作可能會(huì)使得緩沖池中的頁從LRU 鏈表中被刷新出,從而影響緩沖池的效率。常見的這類操作為索引或者數(shù)據(jù)的掃描操作。這類操作需要訪問表中的許多頁,甚至是全部的頁,而這些頁通常來說僅在這次查詢操作中需要,并不是活躍的熱點(diǎn)數(shù)據(jù)。如果頁被放入 LRU 鏈表的首部,那么非??赡軐⑺枰臒狳c(diǎn)數(shù)據(jù)頁從LRU鏈表中移除,而當(dāng)下一次需要讀取該頁時(shí),InnoDB存儲(chǔ)引擎需要再次訪問磁盤,從而導(dǎo)致數(shù)據(jù)庫性能的下降。
此外還需要特別注意的是,有些使用的頁并不存放在 LRU 鏈表中,例如自適應(yīng)哈希,鎖信息。它們雖然同樣通過 free 鏈表申請空間,但是當(dāng)申請完畢時(shí),其并不放入LRU鏈表。所以在輸出的狀態(tài)中可以類似如下的內(nèi)容∶
這里L(fēng)RUlength+Flush list length并不等于Buffer Pool size,還少了505個(gè)頁。原因就在于緩沖池中的部分空間分配給了其他對(duì)象,在上述的例子中是由于自適應(yīng)哈希索引的關(guān)系∶
node heap has 505 buffer(s)顯示了自適應(yīng)哈希索引占用了505個(gè)緩沖池中的頁,可以看到在這里例子中,緩沖池中的頁分配給了自適應(yīng)哈希索引、free 鏈表與LRU鏈表中的頁。
緩沖池中的頁不僅需要被讀取,還需要進(jìn)行修改操作。修改的頁肯定發(fā)生在 LRU鏈表中,當(dāng)LRU鏈表中的頁被修改后,則稱該頁為臟頁(dirty page),即緩沖池中的頁和磁盤上的頁數(shù)據(jù)產(chǎn)生了不一致。這時(shí)數(shù)據(jù)庫會(huì)通過 checkpoint 機(jī)制將臟頁刷新回磁盤。而 flush 鏈表中的頁即為臟頁。需要注意的是,臟頁既存在于LRU鏈表中,也存在于flush鏈表中。LRU鏈表用于管理緩沖池中頁的可用性,flush 鏈表則用干管理將頁刷新回磁盤,兩者互不影響。圖1-3顯示了 free 鏈表、LRU鏈表、flush 鏈表之間的關(guān)系∶
總結(jié)
以上是生活随笔為你收集整理的深入理解MySQL——LRU、Free和Flush 链表的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 超大文本文件编辑器
- 下一篇: linux cmake编译源码,linu