緩存
? 當(dāng)我們?cè)L問一條記錄時(shí)旷祸,要把這個(gè)頁的數(shù)據(jù)都加載到內(nèi)存中并且緩存起來叉庐。在mysql啟動(dòng)時(shí)宏多,就像操作系統(tǒng)申請(qǐng)了一篇連續(xù)的內(nèi)存疯攒,緩沖池——buffer pool嗦随,默認(rèn)128M【闯撸可以通過innodb_buffer_pool_size來修改枚尼。池中的緩存頁默認(rèn)也是16kb
? 每一個(gè)緩存頁會(huì)有對(duì)應(yīng)的控制塊,占用一塊內(nèi)存(約為808字節(jié),5%)筷转,存放了控制信息(表空間編號(hào)姑原、頁號(hào)、緩存頁的地址呜舒、鏈表節(jié)點(diǎn)信息锭汛、鎖和LSN信息)
free鏈表
? 用來管理哪些緩存頁還沒有被占用,也就是空閑的,會(huì)把每一個(gè)空閑緩存頁對(duì)應(yīng)的控制塊加入到free鏈表中.每個(gè)節(jié)點(diǎn)占40字節(jié),是單獨(dú)申請(qǐng)的一塊內(nèi)存空間.每次加載了一個(gè)數(shù)據(jù)頁后,就從free鏈表中取出一個(gè)空閑的緩存頁袭蝗,并把該緩存頁對(duì)應(yīng)的控制塊的信息填上唤殴,然后從free鏈表中移除該控制塊節(jié)點(diǎn)。
緩存頁的哈希處理
? 查找buffer pool中的緩存頁通過表空間號(hào)+頁號(hào)作為key到腥,緩存頁是對(duì)應(yīng)的value朵逝。來組成一個(gè)哈希表
flush鏈表
? 如果一個(gè)緩存頁的數(shù)據(jù)被更新了,說明他是臟頁了乡范,會(huì)把這些臟頁對(duì)應(yīng)的控制塊加入到flush鏈表中去
LRU鏈表
? 如果緩存頁已經(jīng)用滿了配名,如何刪除掉不用的緩存頁呢。通過最近最少使用算法來淘汰(同redis)晋辆,所以需要維護(hù)一個(gè)LUR鏈表渠脉,當(dāng)剛加載到緩存池中時(shí),會(huì)放到鏈表的頭部瓶佳。每一次訪問就把對(duì)應(yīng)的控制塊移動(dòng)到頭部芋膘,這樣尾部的節(jié)點(diǎn)就是最近最少使用的緩存頁了。
? 問題:
預(yù)讀:可能判斷會(huì)讀霸饲,但其實(shí)沒讀
-
全表掃描为朋,會(huì)對(duì)緩沖池進(jìn)行好幾輪換血
解決:
- 把LRU鏈表按照比例分成冷熱兩塊,默認(rèn)冷鏈占37%厚脉,3/8左右习寸。
- 這樣預(yù)讀就會(huì)放在old鏈的頭部
- 全表掃描:首次加載的會(huì)被放到old區(qū)的頭部。且在首次加載后的一定時(shí)間間隔內(nèi)傻工,再次訪問改頁的數(shù)據(jù)融涣,不會(huì)把他放到y(tǒng)oung區(qū)(熱鏈)默認(rèn)1秒童番。
- 只有在熱鏈區(qū)域的1/4后面,才會(huì)被移動(dòng)到LRU鏈表的頭部威鹿,就可以降低調(diào)整的頻率剃斧。
刷新臟頁到磁盤
? 后臺(tái)有線程專門把臟頁刷新到磁盤:
- 從
LRU鏈表
的冷數(shù)據(jù)中刷新一部分頁面到磁盤。從尾部開始如果發(fā)現(xiàn)臟頁就刷新到磁盤 - 從flush中刷新一部分到磁盤
多個(gè)buffer pool實(shí)例
? 如果多線程且并發(fā)高的情況下忽你,單一的pool會(huì)因?yàn)槎嗑€程加鎖而影響處理速度幼东,如果pool比較大的時(shí)候(大于1g,如果小于1g設(shè)置多個(gè)是沒用的)科雳,會(huì)拆分成若干個(gè)小pool根蟹,單獨(dú)申請(qǐng)內(nèi)存空間,這樣多線程并發(fā)訪問時(shí)可以提高并發(fā)能力糟秘。5.7.5之后可以動(dòng)態(tài)調(diào)整pool的大小简逮,這時(shí),重新申請(qǐng)尿赚,再把舊的拷過來太耗時(shí)散庶,所以會(huì)把連續(xù)申請(qǐng)改為chunk為單位申請(qǐng),所以一個(gè)pool是有若干個(gè)chunk組成凌净。包含了若干緩存頁的chunk悲龟。如果pool size變化的時(shí)候就通過chunk增減來完成。不需要重新申請(qǐng)?jiān)購(gòu)?fù)制