之前寫過一篇博文,《不好的MySQL過程編寫習慣》(http://www.cnblogs.com/wingsless/p/5041838.html)。這篇博文里強調了不要迴圈的提交事務,儘量將可以放在一起的SQL同一個事務提交,會快很多很多。博文中提到了redo的問題,因此,結合最近編寫新員工培訓材
之前寫過一篇博文,《不好的MySQL過程編寫習慣》(http://www.cnblogs.com/wingsless/p/5041838.html)。這篇博文里強調了不要迴圈的提交事務,儘量將可以放在一起的SQL同一個事務提交,會快很多很多。博文中提到了redo的問題,因此,結合最近編寫新員工培訓材料的感悟,簡單的介紹一些InnoDB和Redo的事情。
InnoDB的記憶體中有redo log buffer,磁碟上還有redo log file,redo用於在宕機之後恢複數據,保證數據的持久性。
一般來講,最符合ACID的redo工作方式應該是這樣的:事務提交時,記憶體中的redo buffer內容寫入文件中,並刷回磁碟(flush,官方文檔中解釋該動作是將磁碟緩存的數據flush迴文件中)。此時buffer pool中的數據塊被修改成為臟頁,但是並不寫回磁碟中,而是在master thread的迴圈中慢慢寫回去,這樣實際上日誌的寫入和數據文件的寫入不是同步進行的,兩者之間會有一定的時間差,這種方式就叫做預寫日誌(WAL)。一旦系統宕機,記憶體中的數據立刻丟失,下次啟動資料庫時,沒有來得及寫回數據文件的數據可以從redo log中恢復。
因此在上篇博文中的過程,會在每一個事務提交時寫一次日誌,這樣會帶來很多的磁碟IO,因此效率非常低下,而單個事務提交只會造成一次IO,所以效率提升非常顯著。但是,InnoDB還支持另外的一種模式,這個模式由innodb_flush_log_at_trx_commit參數控制,預設情況下是1,代表上面說的那種方式,每次事務提交都會寫redo日誌。
在一次試驗中,我仍然保持存儲過程迴圈提交事務,但是我將參數調整到了2,這樣的效率提升也很明顯,稍微慢於單事務提交。參數為2的意義是,每次提交事務的時候,也會寫日誌文件,但是並不調用fsync函數(刷盤的函數)將日誌刷回磁碟,而是一秒一次的調度fsync函數。因此也會帶來不少的效率提升。這樣做的問題很明顯,如果遇到宕機,會丟失一秒左右的數據。
當然這個參數還能調整成0,代表事務提交時不作任何操作,每隔一秒才會將redo buffer的數據寫入日誌並刷回磁碟中。這種方式看起來就明顯快的多了,但是卻是最不符合ACID原則的做法。
當然了,刷磁碟這個事情還會牽扯一些別的參數,那就不在本文的討論範圍之內了,未來如果有學習心得我會寫下來的。
實際上,如果不在乎一秒的數據丟失(一秒的數據有時候真的很多很多),可以將該參數選擇為2,但是最好還是選擇為1。程式在寫資料庫的時候,可以採用批量提交的方式,速度非常快。這是程式設計的問題了,也不在討論範圍內了。