MySQL InnoDB的缓冲池之预读失效和缓存池污染
InnoDB的緩存池作用:
- 緩存表數據和索引數據,把磁盤上的數據加載到緩沖池中,避免每次都進行磁盤IO,起到加速訪問的效果.
LRU算法(Least recently used):
- 把入緩存池的頁放在LRU的頭部,作為最近訪問的元素
- 頁在緩沖池中的數據,把它放在隊列的前面(情景一)
- 頁不在緩沖池中的數據,把它放在隊列的前面,同時淘汰隊列后面的數據(情景二)
情景一
情景二
MySQL不用LRU算法原因:
- 預讀失效
- 提前把頁放入了緩沖池,但最終MySQL并沒有從頁中讀取數據,稱為預讀失效。
- 緩沖池污染
- 當某一個SQL語句,要批量掃描大量數據時,可能導致把緩沖池的所有頁都替換出去,導致大量熱數據被換出,MySQL性能急劇下降,這種情況叫緩沖池污染。
解決預讀失效的方式:
- 將LRU分為兩部分:
- 新生代
- 老生帶
- 新生代,老生代首尾相連
- 新頁加入緩沖池前,先加入到老生帶頭部
- 如果數據真正的被讀取,才會加入到老生帶中
- 如果數據沒有被讀取,則會比新生代的"熱數據"更早的淘汰出緩沖池
解決MySQL緩沖池污染:
緩沖池污染案例:
有一個數據量較大的用戶表,當執行:select * from user where name like "%shenjian%";雖然結果集可能只有少量數據,但這類like不能命中索引,必須全表掃描,就需要訪問大量的頁:(1)把頁加到緩沖池(插入老生代頭部);(2)從頁里讀出相關的row(插入新生代頭部);(3)row里的name字段和字符串shenjian進行比較,如果符合條件,加入到結果集中;(4)…直到掃描完所有頁中的所有row…如此一來,所有的數據頁都會被加載到新生代的頭部,但只會訪問一次,真正的熱數據被大量換出。?? ?有一個數據量較大的用戶表,當執行:
?? ?select * from user where name like "%shenjian%";
?? ?雖然結果集可能只有少量數據,但這類like不能命中索引,必須全表掃描,就需要訪問大量的頁:
?? ?(1)把頁加到緩沖池(插入老生代頭部);
?? ?(2)從頁里讀出相關的row(插入新生代頭部);
?? ?(3)row里的name字段和字符串shenjian進行比較,如果符合條件,加入到結果集中;
?? ?(4)…直到掃描完所有頁中的所有row…
?? ??
?? ?如此一來,所有的數據頁都會被加載到新生代的頭部,但只會訪問一次,真正的熱數據被大量換出。
解決方案:
MySQL InnoDB數據參數設置:
參數:innodb_buffer_pool_size
介紹:配置緩沖池的大小,在內存允許的情況下,DBA往往會建議調大這個參數,越多數據和索引放到內存里,數據庫的性能會越好。
參數:innodb_old_blocks_pct
介紹:老生代占整個LRU鏈長度的比例,默認是37,即整個LRU中新生代與老生代長度比例是63:37。
畫外音:如果把這個參數設為100,就退化為普通LRU了。
參數:innodb_old_blocks_time
介紹:老生代停留時間窗口,單位是毫秒,默認是1000,即同時滿足“被訪問”與“在老生代停留時間超過1秒”兩個條件,才會被插入到新生代頭部。
總結:
- 緩沖池(buffer pool)是一種常見的降低磁盤訪問的機制;
- 緩沖池通常以頁(page)為單位緩存數據;
- 緩沖池的常見管理算法是LRU,memcache,OS,InnoDB都使用了這種算法;
- InnoDB對普通LRU進行了優化:
- 將緩沖池分為老生代和新生代,入緩沖池的頁,優先進入老生代,頁被訪問,才進入新生代,以解決預讀失效的問題
- 頁被訪問,且在老生代停留時間超過配置閾值的,才進入新生代,以解決批量數據訪問,大量熱數據淘汰的問題
總結
以上是生活随笔為你收集整理的MySQL InnoDB的缓冲池之预读失效和缓存池污染的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2019华为杯研究生数学建模竞赛总结(E
- 下一篇: mysql 字符串拼接 null_mys