文章目錄
一、主要流程
一條mysql的更新語句,內部執行的主要流程如下
mysql > update T set c=c+1 where ID=2;
二、日誌系統
(一) redolog
(二) binlog
(三) 兩階段提交與crash_safe
爲什麼要兩階段提交
詳情不贅述,具體見(極客時間)日誌系統:一條SQL更新語句是如何執行的?
崩潰恢復的規則
- 如果redolog裏面的事務是完整的,也就是有了commit標識,則直接提交
- 如果redolog裏面的事務只有完整的prepare,則判斷對應的事務binlog是否存在並完整,如果是,則提交事務,否則回滾事務
兩階段提交如何保證crash_safe
step1發生crash時,binlog未寫,redolog也還未提交,所以數據庫崩潰恢復後,這個事務會回滾,那由於binlog還沒寫,所以更改也不會傳遞到備庫。
那如果是step2發生了crash呢?由規則2可知,崩潰恢復時事務會提交。
(四) undolog
三、減少隨機IO[1]
(一) 減少隨機寫IO之redolog
由上述的流程可知,redolog的存在減少了寫磁盤的次數,試想,如果redolog不存在的話,那我們每寫一行數據(指insert、update、delete)的時候都需要更新磁盤數據頁,此爲隨機寫,耗費大量時間。而使用redolog的話,我們只需要更新內存數據頁,並將更改記錄在redolog當中即可(像寫日誌這種順序寫,每秒幾萬次沒問題),等到合適的時候,再一次性將整個內存數據髒頁刷入磁盤即可,大大降低了隨機寫IO的次數,提升了性能。
(二) 減少隨機讀IO之Change Buffer[2]
當寫操作(insert、update、delete等)涉及到普通二級索引頁(主鍵具有唯一性約束,不適用)的時候,如果該頁在內存中就直接更新。否則,在不影響數據一致性前提的情況下,Innodb 會將這些更新操作緩存在 change buffer 中,然後在下次讀查詢的時候,將該頁讀入內存,然後執行 change buffer 中與這個數據頁有關的操作(此操作稱爲merge),通過這種方式保證這個數據頁邏輯的正確性。流程圖如下:
Note
- change buffer是可持久化的數據,即會被寫入硬盤(系統表空間ibdata1)當中,該持久化過程由後臺線程完成
- 訪問數據頁會觸發merge,後臺線程也會定期merge,數據庫正常關閉時也會merge
- change buffer優化,僅適用於非唯一普通索引頁,故大量插入的場景最好不要使用唯一索引,若用唯一索引,那麼插入時需要先將數據頁讀入內存以判斷是否滿足唯一性約束,即不可避免隨機IO,當然,此時InnoDB也無需再使用change buffer 了
收益
如果沒有 change buffer,更新數據頁的流程爲:
引入 change buffer後,更新數據頁的流程爲:
對比上述兩個流程可知,change buffer 的引入,使得更新操作減少了一次隨機讀IO(即從磁盤讀數據頁至內存,該步驟是交由其他流程來完成的),實際使用中可發現,普通索引和 change buffer 的配合使用,對數據量大的表更新優化還是很明顯的[4]
Ref
[1] 順序IO和隨機IO
[2] 寫緩衝(change buffer),這次徹底懂了!!!
[3] MySQL · 引擎特性 · Innodb change buffer介紹
[4] (極客時間)普通索引和唯一索引,應該怎麼選擇?
[5] MySQL 之 InnoDB引擎 Change Buffer
[6] (極客時間)日誌系統:一條SQL更新語句是如何執行的?