問了幾人,MySQL changebuffer 這點都沒答對
本文轉載自微信公眾號「yes的練級攻略」,作者yes的練級攻略 。轉載本文請聯yes的練級攻略公眾號。
你好,我是yes。
有位同學問了我兩個關于 change buffer 的問題:
隨后我又挑了幾個問答的用戶提問這兩個問題,發現對 change buffer 的理解都有偏差,于是決定操作一篇。
之前我寫過一篇關于 mysql innodb 所有 buffer 的內容 :總結 mysql 的所有 buffer,一網打盡就這篇了!
里面有提到 change buffer,這篇算是之前那篇的補充吧。
如果對 mysql innodb buffer 不太熟悉,建議先看下我之前總結的內容,這個還是需要點前置知識的。
簡單回顧 change buffer
簡單來說 change buffer 就是一塊內存,存在于 buffer pool 中,當需要修改數據時候,如果這個數據所在頁在 buffer pool,那么萬事大吉,直接在內存也修改。
那假設 buffer pool 里沒有要修改的那個數據頁,這時候該修改怎么辦呢?
假設要執行這個 sql:update table set a= 'yes' where b = 1
第一直覺就是找到 b =1 的數據所在的數據頁,加載到 buffer pool 中,然后進行修改,這里就涉及了從磁盤拉取數據到內存這個動作,我們都知道讀盤的開銷是比較大的。
所以 mysql innodb 搞了個 change buffer,當數據頁不存在 buffer pool 時,mysql innodb 先把更新動作緩存在 change buffer 中,當下次 select b=1 這個數據的時候,將數據加載到 buffer pool 中,同時應用上 change buffer 的修改,這就得到正確的數據了。
圖來自mysql官網
重點
上述的原理不難理解,不過我之前文章提到了一點:
這就是重點,理解了這個就能解答上面那位同學的提問。
change buffer 只能應用非唯一二級索引
聚蔟索引和唯一索引都需要檢查數據的一致性,這就不好先把更新、插入、刪除先緩存在 change buffer 中。
假設現在有一張名為 yes 表,里面有聚蔟索引以及一個(a,b) 的非唯一二級索引,現要執行如下語句:
update yes set b= 'yes的練級攻略' where a = 'yesyes'
思考下,此時能用上 change buffer 嗎?
原則上這條更新語句,mysql 可以選擇聚蔟索引掃,或者應用 (a,b)這個索引。
假設走(a,b)索引。
那問題來了,要走(a,b)索引,不就是要掃描(a,b)的數據嗎,也就是需加載(a,b)索引數據頁到 buffer pool 中,那還用啥 change buffer?
聽起來 change buffer 好像沒啥用啊?
我再加點條件:假設這個表不僅僅有 (a,b)這個索引,還有(c,b)、(d,b)等等這些索引,那么如果我們要修改 b 字段的值,是不是除了聚蔟索引,還需要修改(c,b)、(d,b)等等這些索引?
那 change buffer 的用處就來了!我們可以緩存這些修改,后面再應用,這就大量減少了此次 sql 的隨機磁盤 I/O,提高了性能。
看到這,相信你對 change buffer 應該已經有點感覺了,你可以借著這些感覺,去看下官網的介紹,理解起來更容易:
https://dev.mysql.com/doc/refman/5.7/en/innodb-change-buffer.html
回答問題
第一個問題:insert 用 chang buffer 如何確定主鍵不沖突?
主鍵索引和唯一索引都需要掃描校驗,change buffer 只會緩存那些非唯一二級索引的插入操作。
第二個問題:用 chang buffer 不訪問磁盤,如何得到實際修改行數?
chang buffer 無法應用在主鍵索引(聚蔟索引)和唯一二級索引上,所以這兩個得改,主鍵索引都改了,影響行數就有了。