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