--- title: 一句更新在MySQL底層是如何運作的? date: 2020-01-05 18:23:15 tags: - MySQL thumbnail: /uploads/mysql.jpg --- 繼上一章「[一句查詢在MySQL底層是如何運作的?](https://blakefunteis.github.io/2020/01/05/how-run-a-select-in-mysql)」我們了解了MySQL在一句SQL查詢語句後,如何分析優化和執行該語句。 客戶端 → 連接器 → 分析器 → 優化器 → 執行器 ↘ ↙ 查詢緩存 其實更新語句,同樣也會走這個流程。不過他少了查詢緩存,確切來說他不是少了查詢緩存,而是清除緩存,就如上一章我們所講,如果表有變更,他就會清除該表內的查詢緩存,所以才不建議使用查詢緩存,同時他跟查詢還有幾點不同,這個我們稍後會講到。 過去的時候,不管是工作還是在學進修的機會,我們有非常低的機率會遇到資料庫整個資料異常,需要恢復到一個禮拜前的資料,但是那時候沒有執行資料備份出成為sql檔案,那麼我們要如何把資料庫還原到一個禮拜前的狀態? 這時候就要說更新語句跟查詢語句不一樣的地方了,同時也是今天這主題的兩個主角,就是「[Redo Log 重做日誌](https://en.wikipedia.org/wiki/Redo_log)」和「[Binlog 歸檔日誌](https://baike.baidu.com/item/Mysql%20Binlog#1)」 ### Redo Log 重做日誌  我們平常在外面消費會有記帳的習慣,在還沒有記帳APP的時候,都是先記錄在紙上,但是因為每天都會消費,所以帳越來越多,我們一定還會有一本記帳小本本,來專門記錄所有的帳。如果今天要記帳,那麼我可以有兩種做法 1. 直接拿出記帳小本本,紀錄這筆帳 2. 先記錄在紙上,等回家之後再記錄到記帳小本本上。 在外面很忙或者不好拿出記帳本的時候,我們肯定都是選擇二者,先記錄在紙上,等回家之後再紀錄到記帳本上,因為前者我們必須拿著一本比較重的記帳本,然後還要翻到那一頁的日期再進行紀錄。速度和方便性自然都是第二者比較快比較方便。 同樣的在MySQL也是有相同的問題,如果每次資料都是寫入硬碟(記帳小本本),然後硬碟(記帳小本本)還要找到相應的資料,之後硬碟(記帳小本本)在進行更新,整個IO成本都太高,為了解決這個問題,MySQL的作者也採用了類似上面的方式來解決這問題。 記帳紙和記帳本之間的關係,其實就是MySQL中的 **Write-Ahead Logging** 先寫日誌再寫硬碟,也就是先寫記帳紙,等回家之後或者能抽空的時候在寫記帳本。 當有一條資料要更新的時候,**InnoDB** 會先把紀錄寫進Redo Log(記帳紙)上,並且更新記憶體,到這邊更新其實就算完成了。同時,InnoDB會在適當的時候將這筆更新寫進硬碟,但是這個通常都是資料庫比較空閑的時候才會做的,就像我們回家才會把記帳紙內的帳目紀錄到記帳本上。 Redo Log也是有固定的大小,就像我們的記帳紙一樣,都會有寫滿的一天,那麼當Redo Log被寫滿了,就必須先把部分寫進硬碟,才能為之後新的紀錄騰出空間。這樣即使資料庫發生異常重啟,之前提交的紀錄也不會消失,這個也稱之為「Crash-Safe」。 ### Binlog 歸檔日誌 Redo Log 是InnoDB引擎的特有日誌,而Server本身當然也有自己的日誌就是Binlog。 為什麼會有兩份日誌呢? 因為一開始MySQL並沒有InnoDB的引擎,MySQL自帶的是MyISAM,但是MyISAM沒有Crash-Safe的能力,Binlog又只能用於歸檔。而InnoDB是另一個公司以插件的形式導入MySQL的。既然依靠Binlog無法實現Crash-Safe,那麼InnoDB只好使用另一套日誌Redo Log來實現Crash-Safe,這就是為什麼有兩套日誌的原因。 #### Redo Log和Binlog的差異 1. Redo log是InnoDB獨有,而Binlog是MySQL內建的。 2. Redo log紀錄的是“做了什麼修改”;Binlog則是“某ID=10的欄位A改成100” 3. Redo log是循環寫的,空間會用完,如果要再新增,那麼就要把之前的一些紀錄清除掉;Binlog寫到一定大小後會切換到下一個,並不會覆蓋之前所寫的 了解兩個日誌,我們來看看InnoDB在Update語句時候的流程是什麼 1. 執行器先找InnoDB取出例如ID等於10的,因ID是主鍵,所以會用樹搜索到這一筆資料,如果資料本來就在記憶體中就直接返回給執行器,如果沒有,則從硬碟中取出在寫進記憶體並且返回。 2. 執行器拿到資料後把資料變更為Update所要更改的資料成為新資料,之後直接調用InnoDB寫入新資料。 3. InnoDB將這筆資料寫入記憶體中,同時也會將這筆操作寫入Redo log中。 4. 執行器產生這筆操作的binlog,並且把binlog寫入硬碟。 5. 執行器調用InnoDB的提交接口,InnoDB把剛剛寫入的Redo log改成提交的狀態。 到此一句簡單的更新完成。
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up