成本人视频在线观看_99re这里只有国产中文精品视频88_国产无码合集_肉岳疯狂69式激情的高潮_亚洲狠狠爱综合影院婷婷

當(dāng)前位置: 首頁(yè)  >  >聚焦 > > 正文

天天微資訊!Mysql實(shí)戰(zhàn)之日志系統(tǒng):一條SQL更新語(yǔ)句是如何執(zhí)行的

2023-02-24 06:57:36    來(lái)源:騰訊云

1.前言

上一篇咱們了解了MySQL 的執(zhí)行過(guò)程,其中設(shè)計(jì)連接器、分析器、優(yōu)化器、執(zhí)行器和存儲(chǔ)引擎,接下來(lái)我將給大家講解一下在MySQL中一條更新語(yǔ)句是如何執(zhí)行。我相信大家可能聽(tīng)公司的DBA提起過(guò),可以將數(shù)據(jù)恢復(fù)到半個(gè)月內(nèi)任意時(shí)間的狀態(tài),是不是感覺(jué)很高大上,很厲害呢,下面我就將這個(gè)謎底一步一步解開(kāi)


(資料圖片)

2. 首次分析更新語(yǔ)句執(zhí)行

例如我們存在如下一下update 語(yǔ)句

update order set status = 2 where id = 10;

根據(jù)上一章,我們可以知道它的執(zhí)行流程是如下圖

在這里插入圖片描述

客服端先通過(guò)連接器連接數(shù)據(jù)庫(kù),然后通過(guò)分析器發(fā)現(xiàn)是更新的SQL語(yǔ)句,優(yōu)化器針對(duì)SQL語(yǔ)句進(jìn)行優(yōu)化,使用id索引,最后執(zhí)行器執(zhí)行SQL語(yǔ)句

到這里大家會(huì)說(shuō):這不是和查詢(xún)語(yǔ)句一樣嗎,都是這些流程,其實(shí)不然,更新語(yǔ)句還設(shè)計(jì)兩個(gè)比較重要的模塊,那就是我們今天主要介紹的內(nèi)容:redo log(重做日志)和binlog(歸檔日志)

3.先看redo log

再說(shuō)將redo log之前,先給大家講一個(gè)關(guān)于孔乙己的故事,酒店掌柜有一個(gè)粉板,專(zhuān)門(mén)用來(lái)記錄客人的賒賬記錄。如果賒賬的人不多,那么他可以把顧客名和賬目寫(xiě)到板上。但是如果賒賬的人多了,粉板總會(huì)有記不下的時(shí)候,這個(gè)時(shí)候掌柜一定還有一個(gè)專(zhuān)門(mén)記錄賒賬的賬本。

如果有人要賒賬或者還賬的話(huà),掌柜一般有兩種做法:

直接把賬本拿出來(lái),把此次賒的賬加上或者扣除掉將此次賒的賬記錄到粉板上,等打烊了在把賬本拿出來(lái),把今天的粉板的賬記錄到賬本

如果是在生意比較火的時(shí)候,掌柜肯定會(huì)選擇第二種方式,因?yàn)榈谝环N操作太麻煩了,每次都要從賬本里面找到對(duì)應(yīng)人的賬,進(jìn)行計(jì)算,然后更新賬本。相比之下,先把賬記錄到粉板上,等打烊在一塊統(tǒng)計(jì)到賬本上,更省時(shí)。

MySQL同樣也存在類(lèi)似的問(wèn)題,就是如果每次更新操作都需要寫(xiě)入磁盤(pán),然后磁盤(pán)也要找到對(duì)應(yīng)的記錄,然后更新,整個(gè)過(guò)程IO成本和查找成本都很高。為了解決這個(gè)問(wèn)題,MySQL設(shè)計(jì)者就采取了類(lèi)似掌柜粉板的思路來(lái)提升更新的效率

當(dāng)有更新操作執(zhí)行的時(shí)候,InnoDB引擎就會(huì)先把記錄寫(xiě)到redo log里面,并更新內(nèi)存,這樣更新操作就算結(jié)束了。InnoDB引擎會(huì)在適當(dāng)?shù)臅r(shí)候,將這個(gè)操作記錄更新到磁盤(pán),這個(gè)寫(xiě)磁盤(pán)的操作一般都是在MySQL比較空閑的時(shí)候執(zhí)行。

這里存在一個(gè)問(wèn)題,就是redo log不可能是無(wú)限大的,總有因?yàn)轭l繁操作,將redo log打滿(mǎn)的情況,InnoDB的設(shè)計(jì)人員也考慮到了這一點(diǎn),將redo log設(shè)定成了固定大小,默認(rèn)是一組四個(gè)文件,一個(gè)文件1G,也就是說(shuō)redo log總大小是4GB,下圖就是redo log的設(shè)計(jì)圖

在這里插入圖片描述

wirte pos是記錄當(dāng)前的位置,一邊寫(xiě)一遍后移,寫(xiě)到第三號(hào)文件的末尾就回到0號(hào)文件開(kāi)頭。checkpoint 是當(dāng)前要察除的位置,也是往后推移并且循環(huán)的,察除記錄前要把記錄更新到數(shù)據(jù)文件。

wirte pos和checkpoint 之間還空著的部分,可以用來(lái)記錄新的操作。如果wirte pos追上checkpoint,標(biāo)識(shí)redo log已經(jīng)滿(mǎn)了,此時(shí)不能在執(zhí)行更新操作,需要將內(nèi)存的數(shù)據(jù)同步到磁盤(pán)中了。

有了redo log,InnoDB就可以保證即使數(shù)據(jù)庫(kù)發(fā)生重啟,之前提交的記錄都不會(huì)丟,這個(gè)能力稱(chēng)之為crash-safe。

4.再看binlog

上一篇文章我們講過(guò)數(shù)據(jù)庫(kù)架構(gòu)分為兩層,一個(gè)是server層,一個(gè)是存儲(chǔ)引擎層,而binlog就屬于server層的日志,而redo log是InnoDB獨(dú)有的日志

說(shuō)道這里,大家肯定會(huì)有一個(gè)疑惑,為啥會(huì)有兩個(gè)日志系統(tǒng)呢?

因?yàn)橐婚_(kāi)始MySQL并沒(méi)有InnoDB引擎,MyISAM是MySQL自帶的引擎,但是MyISAM沒(méi)有日志系統(tǒng)的功能,只存在server層的binlog 歸檔日志,InnoDB是后來(lái)集成到mysql里面去的

下面看一下兩種日志的不同點(diǎn)

redo log是InnoDB引擎獨(dú)有的;binlog是mysql共用的redo log是物理日志,記錄的是“在某個(gè)數(shù)據(jù)頁(yè)上做了什么修改”;binlog是邏輯日志,記錄的是這個(gè)語(yǔ)句的原始邏輯,比如給id=2這一行的c字段加1.redo log日志是循環(huán)寫(xiě)的,空間固定會(huì)用完;binlog日志是追加寫(xiě)的,不會(huì)覆蓋以前的日志

5.再次分析更新語(yǔ)句執(zhí)行

上面我們對(duì)兩種日志做了概念性講解,下面看一下執(zhí)行器和InnoDB引擎在執(zhí)行update語(yǔ)句是的內(nèi)部流程

在這里插入圖片描述
執(zhí)行器先找引擎取到id=2的這一行,因?yàn)閕d是主鍵,直接可以通過(guò)主鍵索引查到這一行,如果id=2這一行所在的數(shù)據(jù)頁(yè)本來(lái)就在內(nèi)存中,執(zhí)行器直接放回結(jié)果,如果不在,在需要將磁盤(pán)的數(shù)據(jù),寫(xiě)到內(nèi)存在返回結(jié)果執(zhí)行器會(huì)將id=2的這一行的c字段進(jìn)行加1操作,然后會(huì)更新當(dāng)前行InnoDB引擎將當(dāng)前行更新到內(nèi)存后,redo log日志會(huì)記錄當(dāng)前更新操作,此時(shí)redo log日志處于prepare的狀態(tài)。然后告知執(zhí)行器執(zhí)行完成,可以提交事務(wù)了binlog日志會(huì)記錄當(dāng)前update語(yǔ)句,并且把binlog寫(xiě)入磁盤(pán)執(zhí)行器調(diào)用引擎提交事務(wù),引擎把剛剛寫(xiě)入的redo log改成提交狀態(tài)(commit),更新完成

大家可以看到我們對(duì)redo log日志做了兩次提交,也就是我們平常說(shuō)的兩階段提交

6.兩階段提交

問(wèn):為啥需要進(jìn)行兩階段提交

答:兩階段提交是為了讓binlog和redo log可以保持?jǐn)?shù)據(jù)一致

問(wèn):如果不使用兩階段提交,會(huì)產(chǎn)生什么樣的問(wèn)題?

答:如果不存在兩階段提交,那邊就會(huì)有兩種情況。

先寫(xiě)redo log日志,后寫(xiě)binlog日志。如果我們寫(xiě)完了redo log日志,但是binlog日志還沒(méi)有寫(xiě),發(fā)生了宕機(jī),我們?cè)谥貑ySQL的時(shí)候用binlog恢復(fù)數(shù)據(jù)的話(huà),id=2這一行的數(shù)據(jù)沒(méi)有完成加1操作,和之前庫(kù)的數(shù)據(jù)不一致了先寫(xiě)binlog日志,后寫(xiě)redo log日志。如果我們寫(xiě)完了binlog日志,但是redo log日志還沒(méi)有寫(xiě),發(fā)生了宕機(jī),此時(shí)事務(wù)沒(méi)有生效,我們通過(guò)binlog日志恢復(fù)數(shù)據(jù),發(fā)現(xiàn)id=2這一行已經(jīng)完成加1操作了,和之前庫(kù)的數(shù)據(jù)不一致了

7.小結(jié)

今天主要講了MySQL最重要的兩個(gè)日志,一個(gè)是server層的binlog歸檔日志,一個(gè)是InnoDB引擎的redo log重做日志

redo log 用于保證 crash-safe 能力。innodb_flush_log_at_trx_commit 這個(gè)參數(shù)設(shè)置成 1 的時(shí)候,表示每次事務(wù)的 redo log 都直接持久化到磁盤(pán)。這個(gè)參數(shù)我建議你設(shè)置成 1,這樣可以保證 MySQL 異常重啟之后數(shù)據(jù)不丟失。

sync_binlog 這個(gè)參數(shù)設(shè)置成 1 的時(shí)候,表示每次事務(wù)的 binlog 都持久化到磁盤(pán)。這個(gè)參數(shù)我也建議你設(shè)置成 1,這樣可以保證 MySQL 異常重啟之后 binlog 不丟失。

我還跟你介紹了與 MySQL 日志系統(tǒng)密切相關(guān)的“兩階段提交”。兩階段提交是跨系統(tǒng)維持?jǐn)?shù)據(jù)邏輯一致性時(shí)常用的一個(gè)方案,即使你不做數(shù)據(jù)庫(kù)內(nèi)核開(kāi)發(fā),日常開(kāi)發(fā)中也有可能會(huì)用到。

關(guān)鍵詞: 云數(shù)據(jù)庫(kù) Server

?上一篇: ?下一篇: