1. 程式人生 > >mysql儲存引擎InnoDB插入資料的過程詳解

mysql儲存引擎InnoDB插入資料的過程詳解

https://blog.csdn.net/tangkund3218/article/details/47361705

mysql是目前市面上應用非常廣泛的關係型資料庫.

當插入,更新,刪除等sql語句執行後,mysql為何總能高效,快速的執行,而且不管是斷電,mysql程序崩潰,還是一些其它非正常因素,mysql總能保持資料完整,

本文將帶著這些問題探祕mysql底層預設儲存引擎InnoDB(Mysql5.5之後)的執行過程.

問題: InnoDB事務提交後在底層都幹了什麼?

當提交一個事務時,實際上它幹了如下2件事:

一:  InnoDB儲存引擎把事務寫入日誌緩衝(log buffer),日誌緩衝把事務重新整理到事務日誌.

二:  InnoDB儲存引擎把事務寫入緩衝池(Buffer pool).

做完上面2件事,整個事務提交就完成了.

InnoDB通過事務日誌把隨機IO變成順序IO,這大大的提高了InnoDB寫入時的效能.

因為把緩衝池的髒頁資料重新整理到磁碟可能會涉及大量隨機IO,這些隨機IO會非常慢,通過事務日誌,避開隨機IO,用順序IO替代它.

但如果此時機器斷電或者意外崩潰,那髒頁資料沒重新整理到磁碟,豈不是資料會丟失? 

答案是否定的, mysql意外崩潰後,重啟時.會根據事務日誌重做事務,恢復所有buffer pool中丟失的髒頁.

上面的過程是在未開啟binlog的情況下的執行過程,binlog的基本配置如下: 

#【開啟二進位制日誌】 
log_bin = mysql-bin
server_id = 2 
#【中繼日誌的位置和命名】 
relay_log = mysql-relay-bin
# 【允許備庫將其重放的事件也記錄到自身的二進位制檔案中】
log_slave_updates = 1
#【sync_binlog 實時重新整理】
sync_binlog = 1

binlog的相關情況不再本文的介紹範圍內,不再展開說明.

讓我們來看看InnoDB的快取和檔案關係,如圖1:

圖1

這裡面有幾個核心的元件:

1, 緩衝池(buffer pool).

事務提交後,InnoDB首先在緩衝池中找到對應的頁,把事務更新到緩衝區中.

當重新整理髒頁到磁碟時,緩衝區都幹了什麼?

緩衝區把髒頁拷貝到double write buffer,double wirte buffer把髒頁重新整理到double write磁碟(這也是一次順序IO),再把髒頁重新整理到資料檔案中.

當然緩衝池中還有其他元件,也非常重要,如插入緩衝,該緩衝區是為了高效維護二級非唯一索引所做的優化,把多次IO轉化為一次IO來達到快速更新的目的.這裡不再展開說明.

2, 日誌緩衝(log buffer)

InnoDB使用日誌來減少事務提交時的開銷.因為日誌記錄了事務,就無須在每個事務提交時把緩衝池中的髒塊重新整理到磁碟.因為重新整理緩衝池到磁碟一般是隨機IO.

InnoDB的日誌緩衝有兩個重要的引數需要介紹下:

innodb_log_buffer_size 日誌緩衝區大小(5.6 預設8M,一般不需要設定太大,除非有BLOB欄位)

innodb_flush_log_at_trx_commit  這是InnoDB重新整理事務日誌的策略引數,預設為1. 

重新整理策略值: 

      0,  一秒鐘重新整理一次,事務提交時,不做任何操作.(可能丟失1秒鐘事務資料)
      1,  每次事務都提交重新整理到持久化儲存(預設&最安全)
      2,  每次提交時把日誌緩衝寫到日誌檔案,但並不重新整理.  

1和3的區別是: mysql程序掛了,3不會丟事務. 伺服器斷電或者掛了, 都丟失事務. 把緩衝寫到日誌是簡單的把資料從INNODB的記憶體緩衝轉移到作業系統緩衝.

3, 事務日誌 

這裡面有2個重要的配置引數需要說明下.

2.1)  innodb_log_file_size mysql 5.6預設的大小是50M

2.2)  innodb_log_files_in_group  mysql5.6預設是2,如下圖:

也就是說,InnoDB預設的事務日誌檔案大小總和是100M。這對高效能工作來說可能太小了,有時需要幾百兆甚至幾個G的事務日誌空間.

linux可通過/etc/my.cnf 來修改事務日誌檔案的大小, windows是my.ini配置檔案

innodb日誌是環行方式寫的:當寫到日誌的尾部,會重新跳轉到開頭繼續寫,但不會覆蓋還沒應用到資料檔案的日誌記錄,因為這樣會清理掉已提交事務的唯一持久化記錄.

日誌檔案太小,InnoDB將必須做更多的檢查點,導致更多的日誌寫,在日誌沒有空間繼續寫入前,必須等待變更被應用到資料檔案,寫語句可能會被拖累.

但日誌檔案太大,在崩潰恢復時InnoDB可能不得不做大量的工作,增加恢復時間. 應該在這之間找到平衡,設定合適的日誌大小.

4, 雙寫緩衝

緩衝池重新整理髒頁面到磁碟時,首先把它們寫到雙寫緩衝,然後再把它們寫到所屬的資料區域中.

那豈不是所有的髒頁都需要寫2遍?對,就是寫2遍. 但雙寫緩衝是順序的,對寫衝擊比較小.

有些備庫上可以禁止雙寫緩衝,另外一些檔案系統(ZFS)做了同樣的事,所以沒必要讓InnoDB做2次, innodb_doublewirte 來關閉。

InnoDb用雙寫緩衝來避免頁沒寫完整所導致的資料損壞.


雙寫緩衝的架構如下圖:

     從緩衝池中拷貝頁到double_write_buffer,double_write_buffer重新整理到double_write(共享表空間),再調fsync()同步磁碟

     總結:

               1, InnoDB提交事務過程如下:

                    1.1):  把事務寫入日誌緩衝(log buffer),日誌緩衝把事務重新整理到事務日誌.

                    1.2):  把事務寫入緩衝池(Buffer pool).

               2,  Innodb儲存引擎在事務提交後,是把隨機IO轉化為順序IO來達到快速提交事務的目的.

               3,  每次重新整理髒頁到磁碟,實際上是2次寫頁到磁碟. 

                    3.1):  重新整理髒頁到雙寫緩衝,順序IO

        3.2):  呼叫一次fsync()重新整理到磁碟,隨機IO

               4,  宕機或者意外崩潰重啟mysql時,根據事務日誌來重做日誌恢復緩衝池未來得及重新整理到磁碟的髒頁,保證資料完整性.


最後給大家提一個問題:

Q:  如果發生寫失效(頁16KB資料,只寫了8Kb),可以通過重做日誌進行恢復,為什麼還需要double_write?

<!--  重做日誌中記錄的是對頁的物理操作,如果頁本身已經發生了毀壞,再對其重做是沒有意義的,會發生資料丟失的情況 -->


--------------------- 
作者:鳳凰小兵 
來源:CSDN 
原文:https://blog.csdn.net/tangkund3218/article/details/47361705 
版權宣告:本文為博主原創文章,轉載請附上博文連結!