Buffer Pool緩存頁不夠時,如何淘汰緩存?

      網(wǎng)友投稿 723 2025-03-31

      若BP緩存頁不夠了,咋辦?

      執(zhí)行CRUD都會將磁盤數(shù)據(jù)頁加載到緩存頁,那在加載數(shù)據(jù)到緩存頁時,必然是要加載到空閑緩存頁,所以必須要從free中找個空閑緩存頁,然后把磁盤數(shù)據(jù)頁加載到該空閑緩存頁

      隨著不斷將磁盤數(shù)據(jù)頁加載到空閑緩存頁,free中的空閑緩存頁會越來越少。最終耗盡free中的空閑緩存頁。這時,還要加載數(shù)據(jù)頁到一個空閑緩存頁時,MySQL 該何去何從?

      若所有緩存頁都有數(shù)據(jù)了,那就無法再從磁盤加載新數(shù)據(jù)頁到緩存頁了,則只能淘汰一些緩存頁:把一個緩存頁里被修改過的數(shù)據(jù),刷到磁盤的數(shù)據(jù)頁,然后該緩存頁就能被清空, 變回空閑頁。然后就能將磁盤的新數(shù)據(jù)頁加載到這剛騰出的空閑頁:

      那應(yīng)該把哪個倒霉的緩存頁的數(shù)據(jù)刷盤呢?

      緩存命中率

      現(xiàn)有兩個緩存頁:

      一個緩存頁的數(shù)據(jù),經(jīng)常被修改和查詢,都可以操作緩存,不需要從磁盤加載數(shù)據(jù),這那緩存命中率就很高。這種高級員工就是啥臟活累活,都會接受。

      另一個緩存頁里的數(shù)據(jù),剛從磁盤加載到緩存頁后,被修改和查詢過1次,之后100次請求再沒有一次是修改和查詢該緩存頁數(shù)據(jù)的,那這緩存命中率就有點低了,因為大部分請求還是走磁盤查詢數(shù)據(jù),他們要操作的數(shù)據(jù)不在緩存。這種高級員工啥事都干不了,都還得交給低級員工們干事。

      很顯然,作為領(lǐng)導(dǎo)的你,肯定想把第二個員工裁了吧?

      引入LRU,判斷哪些緩存頁不常用

      如何知曉哪些緩存頁經(jīng)常被訪問,哪些緩存頁很少被訪問?

      這就需要LRU,Least Recently Used,最近最少使用。這樣當緩存頁需空出一個刷盤時,通過LRU鏈表,就能知道最近最少被使用的緩存頁。

      LRU工作原理

      假設(shè)從磁盤加載一個數(shù)據(jù)頁到緩存頁時,就將該緩存頁的描述信息塊放入LRU鏈表頭部,那么只要有數(shù)據(jù)的緩存頁,他都會在LRU里,最近被加載數(shù)據(jù)的緩存頁,都會放到LRU鏈表頭部。

      假設(shè)某緩存頁的描述信息塊本在LRU鏈尾,后續(xù)你只要查詢或修改了該緩存頁數(shù)據(jù),也要將這緩存頁移到LRU鏈頭,即最近被訪問過的緩存頁,一定在LRU鏈頭。

      如此,當無空閑緩存頁時候,就能輕易找出最近最少被訪問的緩存頁去刷盤,即LRU鏈尾的緩存頁,將其刷盤,然后把你需要的磁盤數(shù)據(jù)頁加載到這剛空出的緩存頁。

      表和行等概念和表空間、數(shù)據(jù)頁的關(guān)系

      表、列和行,都是邏輯概念,我們只關(guān)注DB里有一個表,表里有幾個字段,有多少行,但是這些表里的數(shù)據(jù)

      表空間、數(shù)據(jù)頁等是物理概念,在物理層面,表里的數(shù)據(jù)都放在一個表空間,表空間由一堆磁盤上的數(shù)據(jù)文件組成,這些數(shù)據(jù)文件里都存放了表中的數(shù)據(jù),這些數(shù)據(jù)由一個個數(shù)據(jù)頁組織起來

      但這樣的LRU實際運行時會有問題。

      預(yù)讀

      當你從磁盤加載一個數(shù)據(jù)頁時,他可 能會連帶著把該數(shù)據(jù)頁相鄰的其他數(shù)據(jù)頁,也加載到緩存。

      Buffer Pool緩存頁不夠時,如何淘汰緩存?

      現(xiàn)有兩個空閑緩存頁,加載一個數(shù)據(jù)頁時,連帶著把他的一個相鄰數(shù)據(jù)頁也加載到緩存,正好每個數(shù)據(jù)頁放入一個空閑緩存頁!

      然后呢?實際上只有一個緩存頁被訪問,另外一個通過預(yù)讀機制加載的緩存頁,其實無人問津,此時這倆緩存頁可都在LRU鏈表前邊:

      這時,若無空閑頁了,要加載新數(shù)據(jù)頁,就得從LRU鏈表的尾部將“最近最少使用的緩存頁”取出,刷入磁盤,就空出一個緩存頁了。

      若選擇將上圖中LRU尾部那個緩存頁刷盤,然后清空,合理嗎?

      他可是之前一直頻繁被訪問呀,只是這一瞬間,被新加載進的兩個緩存頁給占了LRU鏈表前面的位置,尤是第二個緩存頁,居然還是通過預(yù)讀加載來的,其實根本無人訪問!而這時將LRU鏈表尾部緩存頁刷盤,肯定不合理,最合理的反而是將那LRU鏈表第二個通過預(yù)讀機制加載進的緩存頁給淘汰。

      MySQL預(yù)讀觸發(fā)時機

      參數(shù)innodb_read_ahead_threshold默認56,即若順序訪問了一個區(qū)里的多個數(shù)據(jù)頁,訪問的數(shù)據(jù)頁數(shù)量超過閾值,就會觸發(fā)預(yù)讀,將下個相鄰區(qū)中的所有數(shù)據(jù)頁都加載到緩 存

      若BP里緩存了一個區(qū)里的13個連續(xù)的數(shù)據(jù)頁,而且這些數(shù)據(jù)頁都是比較頻繁會被訪問的,此時直接觸發(fā)預(yù)讀,把這個區(qū)里的其他的數(shù)據(jù)頁都加載到緩存里去。該機制通過參數(shù)innodb_random_read_ahead控制,默認OFF關(guān)閉。

      所以默認主要第一個規(guī)則可能觸發(fā)預(yù)讀,一下將很多相鄰區(qū)里的數(shù)據(jù)頁加載進緩存,這些緩存頁若突然都放在LRU鏈表前面,且他們其實并沒啥人訪問,就會如上圖,導(dǎo)致本就在緩存里的一些頻繁被訪問的緩存頁卻在LRU鏈尾。后續(xù)一旦要淘汰緩存頁,就會將鏈尾的一些頻繁被訪問的緩存頁給淘汰!

      全表掃描

      如:

      SELECT * FROM xxx

      一下子就將表里所有數(shù)據(jù)頁都從磁盤加載到BP。這時他可能會一下子就把這個表的所有數(shù)據(jù)頁都裝入各緩存頁。此時可能LRU鏈表中排在前面的一大串緩存頁,都是全表掃描加載進來的。若此次全表掃描后,后續(xù)幾乎沒用到這個表里的數(shù)據(jù)呢?此時LRU鏈尾可能全都是之前一直被頻繁訪問的那些緩存頁!

      然后當需要淘汰緩存頁時,就會將LRU鏈表尾部一直被頻繁訪問的緩存頁給淘汰掉了,而留下之前全表掃描加載進來的大量的不經(jīng)常訪問的緩存頁。

      為何MySQL設(shè)計預(yù)讀機制,為何有時要把相鄰的一些數(shù)據(jù)頁一次性讀入到Buffer Pool緩存?

      為提升性能。假設(shè)你讀取了數(shù)據(jù)頁01到緩存頁里去,那接下來有可能會接著順序讀取數(shù)據(jù)頁01相鄰的數(shù)據(jù)頁02到緩存頁,是不是可能在讀取數(shù)據(jù)頁02的時候要再次發(fā)起一次磁盤IO?

      所以為優(yōu)化性能,MySQL設(shè)計了預(yù)讀機制,即若在一個區(qū)內(nèi),你順序讀取了好多數(shù)據(jù)頁,比如數(shù)據(jù)頁01~56都被你依次順序讀取了,MySQL覺得你可能接著會繼續(xù)順序讀取后面的數(shù)據(jù)頁。

      此時他干脆提前把后續(xù)一大堆數(shù)據(jù)頁(如數(shù)據(jù)頁57~72)都讀取到Buffer Pool,后續(xù)你再讀取數(shù)據(jù)頁60時,就能直接從Buffer Pool里拿到。

      但現(xiàn)實骨感,預(yù)讀的一大堆數(shù)據(jù)頁要是占據(jù)LRU鏈表前面部分,然而可能這些預(yù)讀的數(shù)據(jù)頁壓根兒后續(xù)無人用,那這預(yù)讀機制對性能不增反減。

      冷熱分離的LRU

      于是,為了解決前面的問題,真正MySQL采取冷熱數(shù)據(jù)分離思想改良了 LRU。

      之前問題都是因為所有緩存頁都混在一個LRU鏈表才導(dǎo)致的,改良版LRU鏈表拆為熱數(shù)據(jù)、冷數(shù)據(jù)兩部分,冷熱數(shù)據(jù)比例由innodb_old_blocks_pct參數(shù)控制,默認37,即冷數(shù)據(jù)占37%。這時的LRU鏈表:

      數(shù)據(jù)頁第一次被加載到緩存時,緩存頁會被放在冷區(qū)的鏈表頭部。

      冷區(qū)緩存頁何時放入熱區(qū)?

      第一次被加載了數(shù)據(jù)的緩存頁都會不停移動到冷區(qū)的鏈表頭部。那為何不放到熱區(qū)頭部呢?

      你剛加載了一個數(shù)據(jù)頁到那個緩存頁,他在冷區(qū)的鏈表頭部,然后立馬(在1ms以內(nèi))就又被訪問了,但之后就再也不訪問了呢?難道這種情況也要把這緩存頁放到熱區(qū)頭部嗎?

      所以MySQL設(shè)innodb_old_blocks_time參數(shù),默認1000,即1000ms:一個數(shù)據(jù)頁被加載到緩存頁之后,在1s后,你又訪問了該緩存頁,他才會被移到熱區(qū)的鏈表頭部。

      MySQL 數(shù)據(jù)庫

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔相應(yīng)法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔相應(yīng)法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:【華為云學院】一次又當學霸,又可以擁有多部P20的機會,你會錯過嗎?掘金23萬億數(shù)字經(jīng)濟 華為云微認證官方上線!
      下一篇:excel 如果顯示為div/0說明什么?(excel表格怎么換行)
      相關(guān)文章
      亚洲色偷偷综合亚洲AV伊人| 亚洲女子高潮不断爆白浆| 亚洲爆乳精品无码一区二区| 亚洲av永久无码精品天堂久久| 亚洲理论片在线中文字幕| 亚洲精品免费视频| 久久久久亚洲精品成人网小说| 亚洲区小说区图片区QVOD| 亚洲熟妇av一区二区三区漫画| 在线精品亚洲一区二区三区| 亚洲另类激情专区小说图片| 亚洲欧洲日本在线| MM131亚洲国产美女久久| 国产精品亚洲mnbav网站| 久久久久亚洲AV无码专区网站| 亚洲日本韩国在线| 日韩精品亚洲aⅴ在线影院| 亚洲熟女少妇一区二区| 国产亚洲精品岁国产微拍精品| 亚洲老妈激情一区二区三区| 亚洲国产精品久久久天堂| 亚洲国产a∨无码中文777| 久久精品亚洲综合| 91精品国产亚洲爽啪在线影院| 中文字幕亚洲综合久久2| 亚洲第一精品电影网| 亚洲一区二区三区精品视频| 香蕉大伊亚洲人在线观看| 亚洲精品无码中文久久字幕| 成人婷婷网色偷偷亚洲男人的天堂| 少妇亚洲免费精品| 亚洲中久无码不卡永久在线观看| 亚洲综合图色40p| 亚洲AV一宅男色影视| 91亚洲一区二区在线观看不卡| 亚洲区视频在线观看| 亚洲 欧洲 视频 伦小说| 久久久久久亚洲精品无码| 亚洲天堂中文字幕在线| 国产亚洲精品资源在线26u| 2022年亚洲午夜一区二区福利 |