當(dāng)內(nèi)存數(shù)據(jù)頁跟磁盤數(shù)據(jù)頁內(nèi)容不一致的時(shí)候,我們稱這個(gè)內(nèi)存頁為“臟頁”。內(nèi)存數(shù)據(jù)寫入到磁盤后,內(nèi)存和磁盤上的數(shù)據(jù)頁的內(nèi)容就一致了,稱為“干凈頁”
刷臟頁的時(shí)間
第一種是“redo log寫滿了,要flush臟頁” 整個(gè)系統(tǒng)就不能再接受更新了,所有的更新都必須堵住。如果你從監(jiān)控上看,這時(shí)候更新數(shù)會(huì)跌為0
第二種是“內(nèi)存不夠用了,要先將臟頁寫到磁盤” 這種情況是常態(tài)
InnoDB用緩沖池(buffer pool)管理內(nèi)存,緩沖池中的內(nèi)存頁有三種狀態(tài):
- 還沒有使用的;
- 使用了并且是干凈頁;
- 使用了并且是臟頁。
InnoDB的策略是盡量使用內(nèi)存,因此對于一個(gè)長時(shí)間運(yùn)行的庫來說,未被使用的頁面很少。
當(dāng)要讀入的數(shù)據(jù)頁沒有在內(nèi)存的時(shí)候,就必須到緩沖池中申請一個(gè)數(shù)據(jù)頁。這時(shí)候只能把最久不使用的數(shù)據(jù)頁從內(nèi)存中淘汰掉:如果要淘汰的是一個(gè)干凈頁,就直接釋放出來復(fù)用;但如果是臟頁呢,就必須將臟頁先刷到磁盤,變成干凈頁后才能復(fù)用
一個(gè)查詢要淘汰的臟頁個(gè)數(shù)太多,會(huì)導(dǎo)致查詢的響應(yīng)時(shí)間明顯變長;
第三種是MySQL空閑時(shí)
第四種是MySQL正常關(guān)閉
刷臟頁的控制策略
innodb_io_capacity 它會(huì)告訴InnoDB你的磁盤能力 設(shè)置成磁盤的IOPS
innodb_max_dirty_pages_pct臟頁比例上限,默認(rèn)值是75% 通過Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total得到的
InnoDB的刷盤速度就是要參考這兩個(gè)因素:一個(gè)是臟頁比例,一個(gè)是redo log寫盤速度
刷臟頁的連坐”機(jī)制
一旦一個(gè)查詢請求需要在執(zhí)行過程中先flush掉一個(gè)臟頁時(shí),這個(gè)查詢就可能要比平時(shí)慢了。而MySQL中的一個(gè)機(jī)制,可能讓你的查詢會(huì)更慢:在準(zhǔn)備刷一個(gè)臟頁的時(shí)候,如果這個(gè)數(shù)據(jù)頁旁邊的數(shù)據(jù)頁剛好是臟頁,就會(huì)把這個(gè)“鄰居”也帶著一起刷掉;而且這個(gè)把“鄰居”拖下水的邏輯還可以繼續(xù)蔓延,也就是對于每個(gè)鄰居數(shù)據(jù)頁,如果跟它相鄰的數(shù)據(jù)頁也還是臟頁的話,也會(huì)被放到一起刷
innodb_flush_neighbors 值為1的時(shí)候會(huì)有上述的“連坐”機(jī)制,值為0時(shí)表示不找鄰居,自己刷自己的
找“鄰居”這個(gè)優(yōu)化在機(jī)械硬盤時(shí)代是很有意義的,可以減少很多隨機(jī)IO。機(jī)械硬盤的隨機(jī)IOPS一般只有幾百,相同的邏輯操作減少隨機(jī)IO就意味著系統(tǒng)性能的大幅度提升
使用的是SSD這類IOPS比較高的設(shè)備的話,建議把innodb_flush_neighbors的值設(shè)置成0
在MySQL 8.0中,innodb_flush_neighbors參數(shù)的默認(rèn)值已經(jīng)是0了