缓冲多少数据_聊点深的:解析MySQL,看看InnoDB 缓冲池(buffer pool) 工作原理
緩沖池的用處
對于使用 InnoDB 作為存儲引擎的表來說,不管是用于存儲用戶數據的索引,還是各種系統數據,都是以頁的形式存放在表空間中的,而所謂的表空間只是 InnoDB 對文件系統上一個或幾個實際文件的抽象,也就實際數據說到底還是存儲在磁盤上的。
磁盤的速度很慢,怎么能配得上“快如閃電”的CPU 呢?
InnoDB 存儲引擎在處理客戶端的請求時,當需要訪問某個頁的數據時,就會把完整的頁的數據全部加載到內存中。
也就是說即使我們只需要訪問一個頁的一條記錄,那也需要先把整個頁的數據加載到內存中。
緩沖池內部組成
緩沖池中默認的緩存頁大小和在磁盤上默認的頁大小是一樣的,一般是16KB。
為了更好的管理這些在緩沖池中的緩存頁,InnoDB為每一個緩存頁都創建了一些所謂的控制信息。
這些控制信息包括該頁所屬的表空間編號、頁號、緩存頁在緩沖池中的地址、鏈表節點信息、一些鎖信息。
緩沖池的一些參數: SHOW VARIABLES LIKE 'innodb_buffer_pool%'; free 鏈表 當最初啟動MySQL服務器的時候,此時并沒有真實的磁盤頁被緩存到緩沖池中,之后隨著程序的運行,會不斷的有磁盤上的頁被緩存到緩沖池中。
從磁盤上讀取一個頁到緩沖池中的時候該放到哪個緩存頁的位置呢?
思路:區分緩沖池中哪些緩存頁是空閑的,哪些已經被使用了。
把所有空閑的緩存頁對應的控制塊作為節點放到一個鏈表中,這個鏈表叫作 free 鏈表。
flush 鏈表
如果我們修改了緩沖池中某個緩存頁的數據,那它就和磁盤上的頁不一致了,這樣的緩存頁也被稱為臟頁(dirty page)。
最簡單的做法就是每發生一次修改就立即同步到磁盤上對應的頁上,但是頻繁的往磁盤中寫數據會嚴重的影響程序的性能。
所以,Innodb 創建了一個存儲臟頁的鏈表,凡是修改過的緩存頁對應的控制塊都會作為一個節點加入到一個鏈表中,在未來的某個時間點進行同步。這個鏈表叫做 flush 鏈表。
緩存不夠的窘境
緩沖池對應的內存大小畢竟是有限的,如果需要緩存的頁占用的內存大小超過了緩沖池大小,也就是已經沒有多余的空閑緩存頁的時候怎么辦?
把某些舊的緩存頁從緩沖池中移除,然后再把新的頁放進來。
移除哪些緩存頁?這就需要引入緩存淘汰機制了。
緩存淘汰機制
緩存淘汰有以下兩個目的:
- 實現淘汰
- 使緩存命中率高
緩存淘汰機制比較常用的是用 LRU (Least recently used)算法。
傳統LRU
LRU 的兩種情況:
(1)頁已經在緩沖池里,那就只做“移至”LRU頭部的動作,而沒有頁被淘汰;
(2)頁不在緩沖池里,除了做“放入”LRU頭部的動作,還要做“淘汰”LRU尾部頁的動作;
在 InnoDB 中,傳統的 LRU 會遇到兩個問題:
(1)預讀失效;
(2)緩沖池污染;
什么是預讀失效?
由于預讀 (Read-Ahead),提前把頁放入了緩沖池,但最終 MySQL 并沒有從頁中讀取數據,稱為預讀失效。
如何對預讀失效進行優化?
要優化預讀失效,思路是:
(1)讓預讀失敗的頁,停留在緩沖池 LRU 里的時間盡可能短;
(2)讓真正被讀取的頁,才挪到緩沖池 LRU 的頭部;以保證,真正被讀取的熱數據留在緩沖池里的時間盡可能長。
具體方法是:
(1)將LRU分為兩個部分:
- new 區(new sublist)
- old 區(old sublist)
(2)兩個區首尾相連,即:new 區的尾(tail)連接著 old 區的頭(head);
(3)新頁(例如被預讀的頁)加入緩沖池時,只加入到 old 區頭部: 如果數據真正被讀取(預讀成功),才會加入到 new 區的頭部 如果數據沒有被讀取,則會比 new 區里的“熱數據頁”更早被淘汰出緩沖池
改進版緩沖池LRU能夠很好的解決“預讀失敗”的問題。
查看系統變量 innodb_old_blocks_pct 的值來確定old區域在LRU鏈表中所占的比例 SHOW VARIABLES LIKE 'innodb_old_blocks_pct';
什么是 MySQL 緩沖池污染? 當某一個SQL語句,要批量掃描大量數據時,可能導致把緩沖池的所有頁都替換出去,導致大量熱數據被換出,MySQL性能急劇下降,這種情況叫緩沖池污染。
例如,有一個數據量較大的用戶表,當執行 select * from user where name like "%test%";
要優化緩沖池污染,思路是:
(1)不讓批量掃描的大量數據進入到 new 區;
(2)讓真正被讀取的頁,才挪到緩沖池 LRU 的頭部;
具體實現: 加入了一個“old 區停留時間”的機制: 在 old 區域的緩存頁進行第一次訪問時就在它對應的控制塊中記錄下來這個訪問時間,如果后續再次訪問的時間與第一次訪問的時間在某個時間間隔內(即該緩存頁在 old 區的存在時間在某個時間間隔內),那么該頁面就不會被從old 區移動到 new 區的頭部。
上述的全表掃描執行:
(1)掃描過程中,需要新插入的數據頁,都被放到old區
(2)一個數據頁會有多條記錄,因此一個數據頁會被訪問多次
(3)由于是順序掃描,數據頁的第一次被訪問和最后一次被訪問的時間間隔不會超過1S,因此還是會留在old區
(4) 繼續掃描,之前的數據頁再也不會被訪問到,因此也不會被移到 new 區,最終很快被淘汰這個間隔時間是由系統變量 innodb_old_blocks_time 控制的。SHOW VARIABLES LIKE 'innodb_old_blocks_time';配置緩沖池時的注意事項 innodb_buffer_pool_size
innodb_buffer_pool_chunk_size ×
innodb_buffer_pool_instances 的倍數(這主要是想保證每一個 緩沖池 實例中包含的 chunk 數量相同)。
查看Buffer Pool的狀態信息
SHOW ENGINE INNODB STATUSG
一些參數如下:
- Total memory allocated :代表 Buffer Pool 向操作系統申請的連續內存空間大小,包括全部控制塊、緩存頁、以及碎片的大小。
- Buffer pool size:代表該 Buffer Pool 可以容納多少緩存頁,單位是頁
- Free buffers:代表當前 Buffer Pool 還有多少空閑緩存頁,也就是 free 鏈表中還有多少個節點。
- Database pages:代表 LRU 鏈表中的頁的數量,包含 new 和 old 兩個區域的節點數量。
- Old database pages:代表 LRU 鏈表 old 區域的節點數量。
- Modified db pages:代表臟頁數量,也就是 flush 鏈表中節點的數量。
總結
1、磁盤太慢,用內存作為緩存很有必要。2、緩沖池本質上是InnoDB向操作系統申請的一段連續的內存空間,可以通過innodb_buffer_pool_size 來調整它的大小。
3、InnoDB 使用了許多鏈表來管理緩沖池。
4、緩沖池的常見管理算法是 LRU
5、InnoDB 對普通 LRU 進行了優化:分為 new 區和 old 區,加入“停留時間”機制。
作者:JeffreyC鏈接:https://juejin.im/post/5eccf7c3f265da76f525d333
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的缓冲多少数据_聊点深的:解析MySQL,看看InnoDB 缓冲池(buffer pool) 工作原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql 同一张表 某个字段更新到另一
- 下一篇: vc2005运行库彻底卸载_解决不安装V