這是在網(wǎng)上找到的一張流程圖唬党,寫的比較好鹃共,大家可以先看圖,然后看詳細(xì)閱讀下面的各個(gè)步驟驶拱。
執(zhí)行流程:
1.連接驗(yàn)證及解析
客戶端與MySQL Server建立連接霜浴,發(fā)送語句給MySQL Server,接收到后會(huì)針對(duì)這條語句創(chuàng)建一個(gè)解析樹蓝纲,然后進(jìn)行優(yōu)化阴孟,(解析器知道語句是要執(zhí)行什么,會(huì)評(píng)估使用各種索引的代價(jià)税迷,然后去使用索引永丝,以及調(diào)節(jié)表的連接順序)然后調(diào)用innodb引擎的接口來執(zhí)行語句。
2.寫undo log
innodb 引擎首先開啟事務(wù)箭养,對(duì)舊數(shù)據(jù)生成一個(gè)反向的UPDATE的語句(如果是INSERT會(huì)生成反向的DELETE語句)慕嚷,用于提交失敗后回滾,寫入undo log毕泌,得到回滾指針喝检,并且更新這個(gè)數(shù)據(jù)行的回滾指針和版本號(hào)(會(huì)設(shè)置為更新的事務(wù)id)。
3.從索引中查找數(shù)據(jù)
根據(jù)查詢條件去B+樹中找到這一行數(shù)據(jù)(如果是唯一性索引撼泛,查到第一個(gè)數(shù)據(jù)就可以了(因?yàn)橛形ㄒ恍约s束)挠说,如果是普通索引,會(huì)把所有數(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 唯一性索引
如果更新的索引是唯一性索引撩炊,判斷更新后是否會(huì)破壞數(shù)據(jù)的唯一性外永,不會(huì)的話就更新內(nèi)存中的數(shù)據(jù)頁崎脉。
4.2 如果數(shù)據(jù)頁不在內(nèi)存中
先判斷更新的索引是普通索引還是唯一性索引拧咳?
4.2.1 普通索引
如果是更新的索引是普通索引,將對(duì)數(shù)據(jù)頁的更新操作記錄到change buffer囚灼,change buffer會(huì)在空閑時(shí)異步更新到磁盤骆膝。
4.2.2 唯一性索引
如果是更新的索引是唯一性索引,因?yàn)樾枰WC更新后的唯一性灶体,所以不能延遲更新阅签,必須把數(shù)據(jù)頁從磁盤加載到內(nèi)存,然后判斷更新后是否會(huì)數(shù)據(jù)沖突蝎抽,不會(huì)的話就更新數(shù)據(jù)頁政钟。
5.寫undo log(prepare狀態(tài))
將對(duì)數(shù)據(jù)頁的更改寫入到redo log,將redo log設(shè)置為prepare狀態(tài)樟结。
6.寫bin log(commit狀態(tài))养交,提交事務(wù)
通知MySQL server已經(jīng)更新操作寫入到redo log 了,隨時(shí)可以提交瓢宦,將執(zhí)行的SQL寫入到bin log日志碎连,將redo log改成commit狀態(tài),事務(wù)提交成功驮履。(一個(gè)事務(wù)是否執(zhí)行成功的判斷依據(jù)是是否在bin log中寫入成功鱼辙。寫入成功后,即便MySQL Server崩潰玫镐,之后恢復(fù)時(shí)也會(huì)根據(jù)bin log倒戏, redo log進(jìn)行恢復(fù)。具體可以看看下面的崩潰恢復(fù)原則)
補(bǔ)充資料:
二段提交制是什么恐似?
更新時(shí)杜跷,先改內(nèi)存中的數(shù)據(jù)頁,將更新操作寫入redo log日志蹂喻,此時(shí)redo log進(jìn)入prepare狀態(tài)葱椭,然后通知MySQL Server執(zhí)行完了,隨時(shí)可以提交口四,MySQL Server將更新的SQL寫入bin log孵运,然后調(diào)用innodb接口將redo log設(shè)置為提交狀態(tài),更新完成蔓彩。
如果只是寫了bin log就提交治笨,那么忽然發(fā)生故障驳概,主節(jié)點(diǎn)可以根據(jù)redo log恢復(fù)數(shù)據(jù)到最新,但是主從同步時(shí)會(huì)丟掉這部分更新的數(shù)據(jù)旷赖。
如果只是寫binlog顺又,然后寫redo log,如果忽然發(fā)生故障等孵,主節(jié)點(diǎn)根據(jù)redo log恢復(fù)數(shù)據(jù)時(shí)就會(huì)丟掉這部分?jǐn)?shù)據(jù)稚照。
MySQL崩潰后,事務(wù)恢復(fù)時(shí)的判斷規(guī)則是怎么樣的俯萌?(以redolog是否commit或者binlog是否完整來確定)
如果 redo log 里面的事務(wù)是完整的果录,也就是已經(jīng)有了 commit 標(biāo)識(shí),則直接提交咐熙;
如果 redo log 里面的事務(wù)只有完整的 prepare弱恒,則判斷對(duì)應(yīng)的事務(wù) binlog 是否存在并完整:a. 如果是,則提交事務(wù)棋恼;b. 否則返弹,回滾事務(wù)。
undo log是什么爪飘?
undo log主要是保證事務(wù)的原子性义起,事務(wù)執(zhí)行失敗就回滾,用于在事務(wù)執(zhí)行失敗后悦施,對(duì)數(shù)據(jù)回滾并扇。undo log是邏輯日志,記錄的是SQL抡诞。(可以認(rèn)為當(dāng)delete一條記錄時(shí)穷蛹,undo log中會(huì)記錄一條對(duì)應(yīng)的insert記錄,反之亦然昼汗,當(dāng)update一條記錄時(shí)肴熏,它記錄一條對(duì)應(yīng)相反的update記錄。)
在事務(wù)提交后顷窒,undo log日志不會(huì)立即刪除蛙吏,會(huì)放到一個(gè)待刪除的鏈表中,有purge線程判斷是否有其他事務(wù)在使用上一個(gè)事務(wù)之前的版本信息鞋吉,然后決定是否可以清理鸦做,簡單的來說就是前面的事務(wù)都提交成功了,這些undo才能刪除谓着。
change buffer是什么(就是將更新數(shù)據(jù)頁的操作緩存下來)
在更新數(shù)據(jù)時(shí)泼诱,如果數(shù)據(jù)行所在的數(shù)據(jù)頁在內(nèi)存中,直接更新內(nèi)存中的數(shù)據(jù)頁赊锚。
如果不在內(nèi)存中治筒,為了減少磁盤IO的次數(shù)屉栓,innodb會(huì)將這些更新操作緩存在change buffer中,在下一次查詢時(shí)需要訪問這個(gè)數(shù)據(jù)頁時(shí)耸袜,在執(zhí)行change buffer中的操作對(duì)數(shù)據(jù)頁進(jìn)行更新友多。
適合寫多讀少的場景,因?yàn)檫@樣即便立即寫了堤框,也不太可能會(huì)被訪問到域滥,延遲更新可以減少磁盤I/O,只有普通索引會(huì)用到胰锌,因?yàn)槲ㄒ恍运饕疲诟聲r(shí)就需要判斷唯一性藐窄,所以沒有必要资昧。
redo log 是什么?
redo log就是為了保證事務(wù)的持久性荆忍。因?yàn)閏hange buffer是存在內(nèi)存中的格带,萬一機(jī)器重啟,change buffer中的更改沒有來得及更新到磁盤刹枉,就需要根據(jù)redo log來找回這些更新叽唱。
優(yōu)點(diǎn)是減少磁盤I/O次數(shù),即便發(fā)生故障也可以根據(jù)redo log來將數(shù)據(jù)恢復(fù)到最新狀態(tài)微宝。
缺點(diǎn)是會(huì)造成內(nèi)存臟頁棺亭,后臺(tái)線程會(huì)自動(dòng)對(duì)臟頁刷盤,或者是淘汰數(shù)據(jù)頁時(shí)刷盤蟋软,此時(shí)收到的查詢請(qǐng)求需要等待镶摘,影響查詢。