流程圖
這是在網(wǎng)上找到的一張流程圖,寫的比較好,大家可以先看圖,然后看詳細(xì)閱讀下面的各個步驟。
執(zhí)行流程:
1.連接驗證及解析
客戶端與MySQL Server建立連接,發(fā)送語句給MySQL
Server,接收到后會針對這條語句創(chuàng)建一個解析樹,然后進行優(yōu)化,(解析器知道語句是要執(zhí)行什么,會評估使用各種索引的代價,然后去使用索引,以及調(diào)節(jié)表的連接順序)然后調(diào)用innodb引擎的接口來執(zhí)行語句。
2.寫undo log
innodb 引擎首先開啟事務(wù),對舊數(shù)據(jù)生成一個UPDATE的語句(如果是INSERT會生成UPDATE語句),用于提交失敗后回滾,寫入undo
log,得到回滾指針,并且更新這個數(shù)據(jù)行的回滾指針和版本號(會設(shè)置為更新的事務(wù)id)。
3.從索引中查找數(shù)據(jù)
根據(jù)查詢條件去B+樹中找到這一行數(shù)據(jù)(如果是唯一性索引,查到第一個數(shù)據(jù)就可以了(因為有唯一性約束),如果是普通索引,會把所有數(shù)據(jù)查找出來。)
4.更新數(shù)據(jù)
首先判斷數(shù)據(jù)頁是否在內(nèi)存中?
4.1 如果數(shù)據(jù)頁在內(nèi)存中
先判斷更新的索引是普通索引還是唯一性索引?
4.1.1 普通索引
如果更新的索引是普通索引,直接更新內(nèi)存中的數(shù)據(jù)頁
4.1.2 唯一性索引
如果更新的索引是唯一性索引,判斷更新后是否會破壞數(shù)據(jù)的唯一性,不會的話就更新內(nèi)存中的數(shù)據(jù)頁。
4.2 如果數(shù)據(jù)頁不在內(nèi)存中
先判斷更新的索引是普通索引還是唯一性索引?
4.2.1 普通索引
如果是更新的索引是普通索引,將對數(shù)據(jù)頁的更新操作記錄到change buffer,change buffer會在空閑時異步更新到磁盤。
4.2.2 唯一性索引
如果是更新的索引是唯一性索引,因為需要保證更新后的唯一性,所以不能延遲更新,必須把數(shù)據(jù)頁從磁盤加載到內(nèi)存,然后判斷更新后是否會數(shù)據(jù)沖突,不會的話就更新數(shù)據(jù)頁。
5.寫undo log(prepare狀態(tài))
將對數(shù)據(jù)頁的更改寫入到redo log,將redo log設(shè)置為prepare狀態(tài)。
6.寫bin log(commit狀態(tài)),提交事務(wù)
通知MySQL server已經(jīng)更新操作寫入到redo log 了,隨時可以提交,將執(zhí)行的SQL寫入到bin log日志,將redo
log改成commit狀態(tài),事務(wù)提交成功。(一個事務(wù)是否執(zhí)行成功的判斷依據(jù)是是否在bin log中寫入成功。寫入成功后,即便MySQL
Server崩潰,之后恢復(fù)時也會根據(jù)bin log, redo log進行恢復(fù)。具體可以看看下面的崩潰恢復(fù)原則)
補充資料:
二段提交制是什么?
更新時,先改內(nèi)存中的數(shù)據(jù)頁,將更新操作寫入redo log日志,此時redo log進入prepare狀態(tài),然后通知MySQL
Server執(zhí)行完了,隨時可以提交,MySQL Server將更新的SQL寫入bin log,然后調(diào)用innodb接口將redo
log設(shè)置為提交狀態(tài),更新完成。
如果只是寫了bin log就提交,那么忽然發(fā)生故障,主節(jié)點可以根據(jù)redo log恢復(fù)數(shù)據(jù)到最新,但是主從同步時會丟掉這部分更新的數(shù)據(jù)。
如果只是寫binlog,然后寫redo log,如果忽然發(fā)生故障,主節(jié)點根據(jù)redo log恢復(fù)數(shù)據(jù)時就會丟掉這部分?jǐn)?shù)據(jù)。
MySQL崩潰后,事務(wù)恢復(fù)時的判斷規(guī)則是怎么樣的?(以redolog是否commit或者binlog是否完整來確定)
如果 redo log 里面的事務(wù)是完整的,也就是已經(jīng)有了 commit 標(biāo)識,則直接提交;
如果 redo log 里面的事務(wù)只有完整的 prepare,則判斷對應(yīng)的事務(wù) binlog 是否存在并完整:a. 如果是,則提交事務(wù);b. 否則,回滾事務(wù)。
undo log是什么?
undo log主要是保證事務(wù)的原子性,事務(wù)執(zhí)行失敗就回滾,用于在事務(wù)執(zhí)行失敗后,對數(shù)據(jù)回滾。undo
log是邏輯日志,記錄的是SQL。(可以認(rèn)為當(dāng)delete一條記錄時,undo
log中會記錄一條對應(yīng)的insert記錄,反之亦然,當(dāng)update一條記錄時,它記錄一條對應(yīng)相反的update記錄。)
在事務(wù)提交后,undo
log日志不會立即刪除,會放到一個待刪除的鏈表中,有purge線程判斷是否有其他事務(wù)在使用上一個事務(wù)之前的版本信息,然后決定是否可以清理,簡單的來說就是前面的事務(wù)都提交成功了,這些undo才能刪除。
change buffer是什么(就是將更新數(shù)據(jù)頁的操作緩存下來)
在更新數(shù)據(jù)時,如果數(shù)據(jù)行所在的數(shù)據(jù)頁在內(nèi)存中,直接更新內(nèi)存中的數(shù)據(jù)頁。
如果不在內(nèi)存中,為了減少磁盤IO的次數(shù),innodb會將這些更新操作緩存在change
buffer中,在下一次查詢時需要訪問這個數(shù)據(jù)頁時,在執(zhí)行change buffer中的操作對數(shù)據(jù)頁進行更新。
適合寫多讀少的場景,因為這樣即便立即寫了,也不太可能會被訪問到,延遲更新可以減少磁盤I/O,只有普通索引會用到,因為唯一性索引,在更新時就需要判斷唯一性,所以沒有必要。
redo log 是什么?
redo log就是為了保證事務(wù)的持久性。因為change buffer是存在內(nèi)存中的,萬一機器重啟,change
buffer中的更改沒有來得及更新到磁盤,就需要根據(jù)redo log來找回這些更新。
優(yōu)點是減少磁盤I/O次數(shù),即便發(fā)生故障也可以根據(jù)redo log來將數(shù)據(jù)恢復(fù)到最新狀態(tài)。
缺點是會造成內(nèi)存臟頁,后臺線程會自動對臟頁刷盤,或者是淘汰數(shù)據(jù)頁時刷盤,此時收到的查詢請求需要等待,影響查詢。
熱門工具 換一換