mysql 计算近30天总金额_mysql┃一条更新语句是怎么执行的???
本文共:3018字
預(yù)計(jì)閱讀時(shí)間:8分鐘
文章首發(fā)于我的微信公眾號(hào):哪兒來(lái)的moon,歡迎大家關(guān)注
mysql┃一條更新語(yǔ)句是怎么執(zhí)行的???
前言
通過(guò)上一篇文章的內(nèi)容,大家已經(jīng)對(duì)mysql的基本架構(gòu)有了了解,我也和大家簡(jiǎn)單的聊了下一條查詢(xún)語(yǔ)句是怎么在mysql中運(yùn)行的。
今天moon就和大家聊聊一條更新語(yǔ)句在mysql中是怎么走完全程的?
讀完今天的文章,你將會(huì)學(xué)到:
??一條更新語(yǔ)句是怎么執(zhí)行的?
??redolog,binlog日志模塊是做什么的?都有哪些作用?
正文
moon上一篇文章和大家聊了,一條查詢(xún)語(yǔ)句執(zhí)行過(guò)程當(dāng)中要經(jīng)過(guò)的模塊,有連接器,查詢(xún)緩存,分析器,優(yōu)化器,執(zhí)行器,存儲(chǔ)引擎。
那么一條更新語(yǔ)句走完一整個(gè)流程又要經(jīng)過(guò)哪些模塊呢?
假設(shè)一張表里只有一個(gè)主鍵id和一個(gè)int字段c
我們從如下代碼開(kāi)始
update T set c=c+1 where ID=2;
其實(shí)查詢(xún)語(yǔ)句走的一套流程,基本上更新語(yǔ)句也會(huì)走一遍,但是更新語(yǔ)句還會(huì)涉及到另外兩個(gè)重要的日志模塊,redolog,binlog。
redolog(重做日志)
首先要告訴大家,redolog是innodb獨(dú)有的,關(guān)于它具體做了什么,moon先和大家舉個(gè)例子,不知道大家有沒(méi)有了解過(guò)從前街邊賣(mài)小吃老板的記賬方式。
每來(lái)一個(gè)人,買(mǎi)一份煎餅,老板都會(huì)在自己的賬單上記住+15元,假如今天第一份收入15元
+15 總金額 15
然后第二份
+15 總金額30
第三份
+15 總金額45
這樣看確實(shí)沒(méi)毛病,記得也很清楚,但是老板生意越來(lái)越好,而且做生意也越來(lái)越復(fù)雜,除了賣(mài)煎餅,還會(huì)賣(mài)其他的東西,價(jià)格也不同,物種琳瑯滿(mǎn)目,并且人也越來(lái)越多,老板就沒(méi)辦法實(shí)時(shí)去計(jì)算了,于是老板改了一種方式,分了兩個(gè)賬單。
第一個(gè)賬單每天只記錄一次總的信息(賬本)
2020年5月5號(hào) 收入5000 支出 1000 凈收入 4000
第二個(gè)賬單記錄每天的細(xì)節(jié)信息(賬單)
2020年5月5日
+15
+16
+48
-23
...........
這樣的話(huà)老板在忙的時(shí)候就不需要管計(jì)算的問(wèn)題,只需要簡(jiǎn)單的記錄下金額就好,省去了低效率的計(jì)算過(guò)程,留在生意不忙的空閑時(shí)間去做。
沒(méi)錯(cuò),redolog在mysql 的日志系統(tǒng)就是類(lèi)似于這種賬單模式,它是先寫(xiě)日志,再寫(xiě)磁盤(pán),也就是先記賬,等不忙的時(shí)候再去計(jì)算寫(xiě)賬本。
具體來(lái)說(shuō),當(dāng)有一條記錄需要更新的時(shí)候,InnoDB引擎就會(huì)先把記錄寫(xiě)到redo log里面,并更新內(nèi)存,這個(gè)時(shí)候更新就算完成了(其實(shí)還沒(méi)有寫(xiě)入磁盤(pán))。同時(shí),InnoDB引擎會(huì)在適當(dāng)?shù)臅r(shí)候(空閑時(shí)間),將這個(gè)操作記錄更新到磁盤(pán)里面。如果今天賬單的記錄不多,掌柜可以等打烊后再整理。但如果某天賬單的特別多,賬本寫(xiě)滿(mǎn)了,又怎么辦呢?這個(gè)時(shí)候掌柜只好放下手中的活兒,把賬單中的一部分賒賬記錄更新到賬本中,然后把這些記錄從賬單上擦掉。與此類(lèi)似,InnoDB的redo log是固定大小的,比如可以配置為一組4個(gè)文件,每個(gè)文件的大小是1GB,那么這個(gè)“賬單”總共就可以記錄4GB的操作。從頭開(kāi)始寫(xiě),寫(xiě)到末尾就又回到開(kāi)頭循環(huán)寫(xiě),如下面這個(gè)圖所示。
記錄點(diǎn)就是記錄你要執(zhí)行的語(yǔ)句是什么,寫(xiě)點(diǎn)就是執(zhí)行記錄點(diǎn)記錄的語(yǔ)句,當(dāng)記錄點(diǎn)追上了寫(xiě)點(diǎn)就會(huì)發(fā)生"內(nèi)存抖動(dòng)",從表面上看就是mysql宕機(jī)了一會(huì)兒,其實(shí)是innodb在執(zhí)行redolog中記錄的內(nèi)容。
有了redo log,InnoDB就可以保證即使數(shù)據(jù)庫(kù)發(fā)生異常重啟,之前提交的記錄都不會(huì)丟失,這個(gè)能力稱(chēng)為crash-safe。
binlog(歸檔日志)
我們剛剛說(shuō)了redolog是innodb獨(dú)有的,那么我們之前也講了,mysql其實(shí)是分為兩塊的,一塊兒是server層,另一塊兒才是存儲(chǔ)引擎層,那么server層的日志是什么?其實(shí)就是我們接下來(lái)要講的binlog。
其實(shí)在最早是只有binlog的,因?yàn)樵谶h(yuǎn)古時(shí)代mysql的存儲(chǔ)引擎只有myisam,redolog是在后期innodb出現(xiàn)的時(shí)候也跟著一起來(lái)的,這兩個(gè)日志也是有很大區(qū)別的。
??redo log是InnoDB引擎特有的;binlog是MySQL的Server層實(shí)現(xiàn)的,所有引擎都可以使用。
??redo log是物理日志,記錄的是“在某個(gè)數(shù)據(jù)頁(yè)上做了什么修改”;binlog是邏輯日志,記錄的是這個(gè)語(yǔ)句的原始邏輯,比如“給ID=2這一行的c字段加1 ”。
??redo log是循環(huán)寫(xiě)的,空間固定會(huì)用完;binlog是可以追加寫(xiě)入的。“追加寫(xiě)”是指binlog文件寫(xiě)到一定大小后會(huì)切換到下一個(gè),并不會(huì)覆蓋以前的日志。
我們來(lái)看看這條更新語(yǔ)句的執(zhí)行流程
update T set c=c+1 where ID=2;
⑴.執(zhí)行器先找引擎取ID=2這一行。ID是主鍵,引擎直接用樹(shù)搜索找到這一行。
如果ID=2這一行所在的數(shù)據(jù)頁(yè)本來(lái)就在內(nèi)存中,就直接返回給執(zhí)行器;
否則,需要先從磁盤(pán)讀入內(nèi)存,然后再返回。
⑵.執(zhí)行器拿到引擎給的行數(shù)據(jù),把這個(gè)值加上1,比如原來(lái)是N,現(xiàn)在就是N+1,得到新的一行數(shù)據(jù),再調(diào)用引擎接口寫(xiě)入這行新數(shù)據(jù)。
⑶.引擎將這行新數(shù)據(jù)更新到內(nèi)存中,同時(shí)將這個(gè)更新操作記錄到redo log里面,此時(shí)redo log處于prepare狀態(tài)。然后告知執(zhí)行器執(zhí)行完成了,隨時(shí)可以提交事務(wù)。
⑷.執(zhí)行器生成這個(gè)操作的binlog,并把binlog寫(xiě)入磁盤(pán)。
⑸.執(zhí)行器調(diào)用引擎的提交事務(wù)接口,引擎把剛剛寫(xiě)入的redo log改成提交(commit)狀態(tài),更新完成。
兩階段提交
細(xì)心的已經(jīng)發(fā)現(xiàn)上圖是先寫(xiě)redolog,準(zhǔn)備階段,之后再寫(xiě)binlog,提交事務(wù),commit階段。
為什么會(huì)有兩階段提交呢?
我們先來(lái)看看,如果不適用兩階段提交會(huì)有什么問(wèn)題呢?
??先寫(xiě)redo log后寫(xiě)binlog。假設(shè)在redo log寫(xiě)完,binlog還沒(méi)有寫(xiě)完的時(shí)候,MySQL進(jìn)程異常重啟。由于我們前面說(shuō)過(guò)的,redo log寫(xiě)完之后,系統(tǒng)即使崩潰,仍然能夠把數(shù)據(jù)恢復(fù)回來(lái),所以恢復(fù)后這一行c的值是1。
但是由于binlog沒(méi)寫(xiě)完就crash了,這時(shí)候binlog里面就沒(méi)有記錄這個(gè)語(yǔ)句。因此,之后備份日志的時(shí)候,存起來(lái)的binlog里面就沒(méi)有這條語(yǔ)句。
然后你會(huì)發(fā)現(xiàn),如果需要用這個(gè)binlog來(lái)恢復(fù)臨時(shí)庫(kù)的話(huà),由于這個(gè)語(yǔ)句的binlog丟失,這個(gè)臨時(shí)庫(kù)就會(huì)少了這一次更新,恢復(fù)出來(lái)的這一行c的值就是0,與原庫(kù)的值不同。
??先寫(xiě)binlog后寫(xiě)redo log。如果在binlog寫(xiě)完之后crash,由于redo log還沒(méi)寫(xiě),崩潰恢復(fù)以后這個(gè)事務(wù)無(wú)效,所以這一行c的值是0。但是binlog里面已經(jīng)記錄了“把c從0改成1”這個(gè)日志。所以,在之后用binlog來(lái)恢復(fù)的時(shí)候就多了一個(gè)事務(wù)出來(lái),恢復(fù)出來(lái)的這一行c的值就是1,與原庫(kù)的值不同。
可以看到,如果不使用“兩階段提交”,那么數(shù)據(jù)庫(kù)的狀態(tài)就有可能和用它的日志恢復(fù)出來(lái)的庫(kù)的狀態(tài)不一致。
結(jié)語(yǔ)
今天moon和大家聊了一下mysql中最重要的兩個(gè)日志模塊,innodb專(zhuān)屬的redolog還有server層的binlog,相信大家也對(duì)一條更新語(yǔ)句的執(zhí)行流程有了了解,當(dāng)然這只是概述,我會(huì)在后期講的越來(lái)越細(xì)。
下期就和大家了解了解mysql的索引模型,我們下期見(jiàn)~
借鑒:丁奇《mysql45講》
總結(jié)
以上是生活随笔為你收集整理的mysql 计算近30天总金额_mysql┃一条更新语句是怎么执行的???的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 爷爷带着6岁孙女连续多年到考场拍照 让孩
- 下一篇: mysql sys 数据库_mysql