一條SQL更新語句的執行過程

若是執行這條更新語句數據庫是如何執行的呢?mysql

update Student set name='小明'  where  StudentID=1

根據以前說過的SQL語句查詢的流程來講,只要表上有數據更新,有關查詢的索引就會失效,接下來分析器會根據每一個單詞識別知道這是Update語句,優化器根據這個ID獲取須要的索引,而後執行器執行這一行,進行更新。sql

先說裏面有一個重要的內容就是:redo log(重作日誌)和 binlog(歸檔日誌)。數據庫

重作日誌

在MySQL語句更新的時候,若是每一次更新操做都須要寫進磁盤,而後磁盤也找到對應的記錄,而後再更新,會消耗很大的IO,下降系統的效率。優化

這個時候重作日誌的場景就來了,當一條數據進行更新的時候,InnoDB引擎會先把記錄寫在redo log日誌中,並更新內存完成更新。在系統空閒的時候引擎會把這個操做記錄更新到磁盤。日誌

可是若是一直在往redo log中寫入數據,redo log日誌也是有固定大小的,當寫滿了,會將最以前插入進來的數據,更新到磁盤,而後擦除這段數據能夠用來記錄新的操做。有了這個功能,MySQL在異常重啓狀況下數據都不會丟失。這個能力稱爲crash-safe。code

歸檔日誌

當時MySQL沒有InnoDB引擎,只有歸檔日誌binlog,所以其餘引擎沒有crash-safe功能,後面有了InnoDB才誕生redo log日誌。索引

兩種日誌的特色:接口

  • redo log是屬InnoDB引擎,binlog是屬於Mysql Server實現的。
  • redo log是循環寫的,寫滿了會從頭清空一部分繼續寫,一邊又一遍,binlog是能夠追加寫入,文件滿了又會開闢下一個文件繼續寫。
  • redo log是物理日誌,記錄了在什麼地方進行了修改,而binlog記錄的是更新的具體邏輯,把ID爲二的數據名稱改成小明。

Update語句更新流程

  1. 首先執行器根據StudentID=1的索引取得這一行數據,若是這一行數據在內存中,就直接返回給執行器,否者從磁盤讀取進內存再返回。
  2. 執行器拿到數據給name改成小明,獲得新的數據行。
  3. 引擎將這個數據更新到內存中,而後將操做記錄寫入redo log,這時redo log處於prepare狀態,而後告知執行器已經完成能夠提交事務。
  4. 執行器生成這個操做的binlog,並把binlog寫進磁盤。
  5. 執行器調用引擎接口提交事務,並把剛剛寫入的redo log 改爲提交(commit)狀態,更新完成

爲何要進行兩次提交

若是不用兩次提交會發生什麼狀況事務

假如不用redo log,在系統崩潰的時候,數據就沒有了。內存

假如不用binlog,沒法用binlog恢復數據庫備份。

爲何要兩種一塊兒用呢,就比如事務,寫入了redo log,即將寫入binlog的時候系統崩潰,你的redo log沒有丟失,能夠等系統正常運行的的時候,再次提交併把binlog寫進磁盤。redo log 和 binlog 均可以用於表示事務的提交狀態,而兩階段提交就是讓這兩個狀態保持邏輯上的一致。

redo log 用於保證 crash-safe 能力。innodb_flush_log_at_trx_commit 這個參數設置成1 的時候,表示每次事務的 redo log 都直接持久化到磁盤。這個參數我建議你設置成 1,這樣能夠保證 MySQL 異常重啓以後數據不丟失。

sync_binlog 這個參數設置成 1 的時候,表示每次事務的 binlog 都持久化到磁盤。這個參數我也建議你設置成 1,這樣能夠保證 MySQL 異常重啓以後 binlog 不丟失。
相關文章
相關標籤/搜索