一條更新SQL在MySQL數據庫中是如何執行的

前邊的在《一條SQL查詢在MySQL中是怎麼執行的》中咱們已經介紹了執行過程當中涉及的處理模塊,包括鏈接器、分析器、優化器、執行器、存儲引擎等。今天咱們來一塊兒看看一條更新語句又是怎麼一個執行流程。
mysql

查詢語句的一套執行流程,更新語句也會一樣的走一步,下邊咱們在對照上次文章中的圖來簡單的看一下:sql

圖片


首先,在執行語句前要先鏈接數據庫,這是第一步中鏈接器的工做,前面咱們也說過,當一個表有更新的時候,跟這個表有關的查詢緩存都會失效,因此咱們通常不建議使用查詢緩存。
數據庫

接下來,分析器會通過語法分析和詞法分析,知道了這是一條更新語句後,優化器決定要使用哪個索引,而後執行器負責具體的執行,先找到這一行,而後作更新。緩存

與查詢語句更新不一樣的是,更新流程還涉及兩個重要的日誌,這個咱們在前邊的文章中也有專門的介紹,有興趣的能夠找一下上週的文章《MySQL的兩個日誌系統》,這裏就很少作介紹了。ide

下邊經過一個簡單的例子來分析一下更新操做的流程。優化

咱們先建立一張表,這個表有主鍵ID和一個整型字段c:spa

mysql> create table demo T (ID int primarty ,c int);

而後將ID=2的這一行的值加13d

mysql> update table demo set c = c + 1 where ID = 2;

接下來咱們來看看update語句的執行流程,圖中淺色框表示在存儲引擎中執行的,色框表明的是執行器中執行的。日誌

圖片

咱們能夠看到最後的時候,寫redolog的時候分了兩步,prepare和commit,這就是咱們常說的「兩階段提交」。code

爲何日誌須要「兩階段提交」?

因爲redo log和binlog分別是存儲引擎和執行器的日誌,是兩個獨立的邏輯,若是不用兩階段提交,不管先提交哪一個後提交哪一個都會存在一些問題。咱們這裏也藉助上邊的例子看一下,假設當前ID=2的這一行值爲0 ,在update的過程當中寫完了第一個日誌後,第二個日誌還沒寫期間發生了crash,會怎麼樣?

  • 先寫redolog後寫binlog。假設redolog寫完,binlog還沒寫完,MySQL進程異常重啓了。咱們知道,redolog寫完之後,系統即便崩潰了,也能夠將數據恢復,因此在MySQL重啓後,這一行會被恢復成1。因爲binlog沒寫完就crash,這時候binlog裏面是沒有這個語句的,所以以後備份日誌的的時候,存起來的binlog日誌也沒有這一條語句。當咱們須要經過binlog來恢復數據的時候,因爲binlog丟失了這條語句,恢復出來的這一行的值就是0,與原庫的值不同啦。

  • 先寫binlog後寫redo log。若是寫完buglog以後,redo log還沒寫完的時候發生 crash,若是這個時候數據庫奔潰了,恢復之後這個事務無效,因此這一行的值仍是0,可是binlog裏已經記載了這條更新語句的日誌,在之後須要用binlog來恢復數據的時候,就會多了一個事務出來,執行這條更新語句,將值從0更新成1,與原庫中的0就不一樣了。

咱們能夠看到若是不使用「兩階段提交",那麼數據庫的狀態就會和用日誌恢復出來的庫不一致。雖然平時用日誌恢復數據的機率比較低,可是用日誌最多的仍是擴容的時候,用全量備份和binlog來實現的,這個時候就可能致使線上的主從數據庫不一致的狀況。

相關文章
相關標籤/搜索