InnoDB 原理篇:Change Buffer 是如何提升索引性能的?
前言
大家好,我是阿星。
相信很多小夥伴設計索引時,考慮更多的是索引是否能覆蓋大部分的業務場景,卻忽略了索引的性能。
什麼?不同的索引,性能還不一樣?
是的,這要從change buffer
說起。
Change Buffer 是什麼
MySQL
在啓動成功後,會向內存申請一塊內存空間,這塊內存空間稱爲Buffer Pool
。
Buffer Pool
內維護了很多內容,比如緩存頁、各種鏈表、redo log buff、change buffer 等等。
回到正題,change buffer
是用來幹嘛的?
當索引字段內容發生更新時(update、insert、delete
),要更新對應的索引頁,如果索引頁在Buffer Pool
裏命中的話,就直接更新緩存頁。
否則,InnoDB
會將這些更新操作緩存在change buffer
中,這樣就無需從硬盤讀入索引頁。
下次查詢索引頁時,會將索引頁讀入Buffer Pool
,然後將change buffer
中的操作應用到對應的緩存頁,得到最新結果,這個過程稱爲merge
,通過這種方式就能保證數據邏輯的正確性。
不難看出,change buffer
通過減少硬盤隨機 IO 讀與提高內存利用率,讓數據庫的併發能力更強。
如果不瞭解 Buffer Pool、redo log、索引頁是什麼,可以看看阿星之前寫的幾篇文章
持久化
看到這裏小夥伴有疑問了,change buffer
在內存中,如果萬一MySql
實例掛了或宕機了,這次的更新操作不全丟了嗎?
其實不用擔心,InnoDB
對這塊有相應的持久化方案,會有後臺線程定期把change buffer
持久化到硬盤的系統表空間(ibdata1
)。
並且每次change buffer
記錄的內容,會寫入到redo log buff
中,由後臺線程定期將redo log buff
持久化到硬盤的redolog
日誌。
最後MySql
重啓,可以通過ibdata1
或redolog
恢復change buffer
,恢復的過程,分爲下面幾種情況
-
change buffer
的數據刷盤到ibdata
,直接根據ibdata
恢復 -
change buffer
的數據未刷盤,redolog
裏記錄了change buffer
的內容
-
change buffer
寫入redo log
,redo log
雖做了刷盤但未commit
,binlog
未刷盤, 這部分數據丟失 -
change buffer
寫入redolog
,redolog
雖做了刷盤但未commit
,binlog
已刷盤, 先從binlog
恢復redolog
, 再從redolog
恢復change buffe
-
change buffer
寫入redolog
,redolog
和binlog
都已刷盤,直接從redolog
裏恢復。
如果不清楚redolog
與binlog
的可以看看下面這幾篇文章
如何使用 Change Buffer
看到這裏,相信大家對change buffer
有了基本的認識。
現在可以展開講講change buffer
的使用限制。
是的,你沒聽錯,change buffer
不能隨隨便便用。
一般我們可以把常用索引分類爲下面幾種
其中聚簇索引和唯一索引是無法使用change buffer
,因爲它們具備唯一性。
當更新唯一索引字段的內容時,需要把相應的索引頁加載進Buffer Pool
,驗證唯一性約束,此時都已經讀入到Buffer Pool
了,那直接更新會更快,沒必要使用change buffer
。
也就是說,只有非唯一索引才能使用change buffer
業務場景
那現在有一個問題,使用change buffer
一定可以起到加速作用嗎?
相信大家都清楚merge
的時候是將change buffer
記錄的操作應用到索引頁。
所以索引頁merge
之前,change buffer
記錄的越多收益就越大。
因此對於寫多讀少的業務場景,索引頁在寫完以後馬上被訪問到的概率很小,此時change buffer
的收益最高。
相反,讀多寫少的業務場景,更新完馬上做查詢,則會觸發change buff
立即merge
, 不但硬盤隨機IO次
沒有減少,還增加change buffer
的維護成本。
因此change buff
適合寫多讀少的業務場景
選擇索引
由於唯一索引用不上change buffer
的優化機制,在業務可以接受的情況下,從性能角度出發建議考慮非唯一索引
如果所有的更新後面,都馬上伴隨着對這個記錄的查詢,應該關閉change buffer
,innodb_change_buffering
設置爲none
表示關閉change buffer
。
而在其他情況下change buffer
都能提升更新性能。
我們可以通過innodb_change_buffer_max_size
來動態設置change buffer
佔用的內存大小,假設參數設置爲50
的時候,表示change buffer
的大小最多隻能佔用buffer pool
的 50%
。
最後留個思考題,如果知道redo log
一定清楚WAL
機制,change buffer
與WAL
分別提升性能的側重點是什麼?
關於我
阿星是一個熱愛技術的 Java
程序猿,公衆號 「程序猿阿星」 定期分享有趣有料的精品原創文章!
程序猿阿星 一起成長進階!專注技術原理、源碼,通過圖解方式輸出技術,這裏將會分享操作系統、計算機網絡、Java、分佈式、數據庫等精品原創文章
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/S7-LI5FdfDuogFrN8vJZ8Q