一條update SQL語句是如何執行的
一條更新語句的執行過程和查詢語句類似,更新的流程涉及兩個日誌:redo log(重做日誌)和binlog(歸檔日誌)。比如我們要將ID(主鍵)=2這一行的值加(c:欄位)1,SQL語句如下:
update T set c=c+1 where ID=2;
- redo log
重做日誌是InnoDB引擎特有的,是物理日誌,記錄在“某個資料頁上做了什麼修改“。大小是固定,可以進行配置大小。假如我們配置一組4個檔案,圖中write pos是當前記錄的位置,往後推移並且迴圈;checkpoint是當前要擦除的位置,移動規律和前者一樣。兩者之間的位置可以記錄新的操作。
如果write pos 追上checkpoint,就移動checkpoint擦除一些記錄。所以即使資料可以發生異常重啟,InnoDB也可以保證之前提交的記錄不會丟,這就是MySQL的crash_safe
- binlog
歸檔日誌是MySQL的server層的實現的,所有引擎都可以使用。binlog記錄的是sql語句的原始邏輯,比如根劇'id'欄位查詢所有的資訊;相比redo log的迴圈寫入,binlog是追加寫的,binlog檔案寫到一定大小後會切換到下一個,不會覆蓋以前的日誌。
Binlog有兩種模式,statement 格式的話是記sql語句, row格式會記錄行的內容,記兩條,更新前和更新後都有。
上述語句在InnoDB中的執行流程如下:深色代表在執行器中執行的,淺色是在儲存引擎中。
最後寫入redolog分為了prepare和commit兩步,用來保證兩個日誌寫入的一致性,這就是“兩階段提交”。比如我們執行“update T set status = 1“時:
- 如果寫入redolog成功,但寫binlog失敗,重啟恢復時,資料庫發現沒有commit,那麼事務本身回滾;備份恢復時沒有binlog,資料庫裡的status值不變。
- 如果在commit失敗,重啟恢復時redolog和binlog一致,重新commit;備份恢復時有binlog,直接恢復。
總的來說binlog記錄了對資料庫所有的邏輯操作,可以通過binlog來備份出一份完全相同的庫;因為redolog是InnoDB引擎特有的,如果使用其他引擎,那麼就要依賴binlog來記錄操作。
思考一個問題:定期全量備份的週期“取決於系統重要性,有的是一天一備,有的是一週一備”。那麼在什麼場景下,一天一備會比一週一備更有優勢呢?或者說,它影響了這個資料庫系統的哪個指標?
一天一備,那麼如果需要恢復資料的話,只要保證當天的binlog完整即可;一週一備的話就要保證一週的binlog完整;同時頻繁全量備份需要更多儲存空間,如何選擇取決於業務的重要性,對應的指標是RTO(目標恢復時間)。