【大廠面試04期】講講一條MySQL更新語句是怎麼執行的?

NotFound9發表於2020-06-05

流程圖

這是在網上找到的一張流程圖,寫的比較好,大家可以先看圖,然後看詳細閱讀下面的各個步驟。

執行流程:

1.連線驗證及解析

客戶端與MySQL Server建立連線,傳送語句給MySQL Server,接收到後會針對這條語句建立一個解析樹,然後進行優化,(解析器知道語句是要執行什麼,會評估使用各種索引的代價,然後去使用索引,以及調節表的連線順序)然後呼叫innodb引擎的介面來執行語句。

2.寫undo log

innodb 引擎首先開啟事務,對舊資料生成一個UPDATE的語句(如果是INSERT會生成UPDATE語句),用於提交失敗後回滾,寫入undo log,得到回滾指標,並且更新這個資料行的回滾指標和版本號(會設定為更新的事務id)。

3.從索引中查詢資料

根據查詢條件去B+樹中找到這一行資料(如果是唯一性索引,查到第一個資料就可以了(因為有唯一性約束),如果是普通索引,會把所有資料查詢出來。)

4.更新資料

首先判斷資料頁是否在記憶體中?

4.1 如果資料頁在記憶體中

先判斷更新的索引是普通索引還是唯一性索引?

4.1.1 普通索引

如果更新的索引是普通索引,直接更新記憶體中的資料頁

4.1.2 唯一性索引

如果更新的索引是唯一性索引,判斷更新後是否會破壞資料的唯一性,不會的話就更新記憶體中的資料頁。

4.2 如果資料頁不在記憶體中

先判斷更新的索引是普通索引還是唯一性索引?

4.2.1 普通索引

如果是更新的索引是普通索引,將對資料頁的更新操作記錄到change buffer,change buffer會在空閒時非同步更新到磁碟。

4.2.2 唯一性索引

如果是更新的索引是唯一性索引,因為需要保證更新後的唯一性,所以不能延遲更新,必須把資料頁從磁碟載入到記憶體,然後判斷更新後是否會資料衝突,不會的話就更新資料頁。

5.寫undo log(prepare狀態)

將對資料頁的更改寫入到redo log,將redo log設定為prepare狀態。

6.寫bin log(commit狀態),提交事務

通知MySQL server已經更新操作寫入到redo log 了,隨時可以提交,將執行的SQL寫入到bin log日誌,將redo log改成commit狀態,事務提交成功。(一個事務是否執行成功的判斷依據是是否在bin log中寫入成功。寫入成功後,即便MySQL Server崩潰,之後恢復時也會根據bin log, redo log進行恢復。具體可以看看下面的崩潰恢復原則)

補充資料:

二段提交制是什麼?

更新時,先改記憶體中的資料頁,將更新操作寫入redo log日誌,此時redo log進入prepare狀態,然後通知MySQL Server執行完了,隨時可以提交,MySQL Server將更新的SQL寫入bin log,然後呼叫innodb介面將redo log設定為提交狀態,更新完成。
如果只是寫了bin log就提交,那麼忽然發生故障,主節點可以根據redo log恢復資料到最新,但是主從同步時會丟掉這部分更新的資料。
如果只是寫binlog,然後寫redo log,如果忽然發生故障,主節點根據redo log恢復資料時就會丟掉這部分資料。
MySQL崩潰後,事務恢復時的判斷規則是怎麼樣的?(以redolog是否commit或者binlog是否完整來確定)
如果 redo log 裡面的事務是完整的,也就是已經有了 commit 標識,則直接提交;

如果 redo log 裡面的事務只有完整的 prepare,則判斷對應的事務 binlog 是否存在並完整:a. 如果是,則提交事務;b. 否則,回滾事務。

undo log是什麼?

undo log主要是保證事務的原子性,事務執行失敗就回滾,用於在事務執行失敗後,對資料回滾。undo log是邏輯日誌,記錄的是SQL。(可以認為當delete一條記錄時,undo log中會記錄一條對應的insert記錄,反之亦然,當update一條記錄時,它記錄一條對應相反的update記錄。)
在事務提交後,undo log日誌不會立即刪除,會放到一個待刪除的連結串列中,有purge執行緒判斷是否有其他事務在使用上一個事務之前的版本資訊,然後決定是否可以清理,簡單的來說就是前面的事務都提交成功了,這些undo才能刪除。
change buffer是什麼(就是將更新資料頁的操作快取下來)
在更新資料時,如果資料行所在的資料頁在記憶體中,直接更新記憶體中的資料頁。
如果不在記憶體中,為了減少磁碟IO的次數,innodb會將這些更新操作快取在change buffer中,在下一次查詢時需要訪問這個資料頁時,在執行change buffer中的操作對資料頁進行更新。
適合寫多讀少的場景,因為這樣即便立即寫了,也不太可能會被訪問到,延遲更新可以減少磁碟I/O,只有普通索引會用到,因為唯一性索引,在更新時就需要判斷唯一性,所以沒有必要。

redo log 是什麼?

redo log就是為了保證事務的永續性。因為change buffer是存在記憶體中的,萬一機器重啟,change buffer中的更改沒有來得及更新到磁碟,就需要根據redo log來找回這些更新。
優點是減少磁碟I/O次數,即便發生故障也可以根據redo log來將資料恢復到最新狀態。
缺點是會造成記憶體髒頁,後臺執行緒會自動對髒頁刷盤,或者是淘汰資料頁時刷盤,此時收到的查詢請求需要等待,影響查詢。

相關文章