MySQL技術內幕Chapter7事務
一、事務分類
1.扁平事務
使用最為頻繁的事務,主要限制在於不能提交或者回滾事務的某一部分
2.帶有儲存點的事務
允許事務在執行過程中回滾到同一事務中較早的一個狀態,儲存點使用SAVEWORK函式建立,通知系統當前處理狀態。
3.鏈事務
帶有儲存點的扁平事務在系統崩潰時都將消失,其儲存點是易失的,當進行恢復時,事務需要從頭開始執行,而非最近的儲存點。
鏈事務思想在於:提交事務時,釋放不需要的資料物件,將必要的處理上下文隱式的傳給下一個要開始的事務。提交事務操作和下一個事務操作將合併為一個原子操作。
鏈事務與帶有儲存點的事務不同之處在於回滾只能是當前事務,而非任意儲存點。
4.巢狀事務
任何子事務都在頂層事務提交後才生效
任意事務的回滾都會引起所有子事務的回滾
實際工作由葉節點事務完成,而高層的事務僅負責邏輯控制
5.分散式事務
二、事務的實現
1.redo
undo與redo區別:前者負責資料庫事務的一致性,後者是資料庫事務的原子性與永續性。redo恢復提交事務修改的頁操作,而undo回滾行記錄到某個特定的版本。redo是物理日誌,記錄頁的物理修改操作,undo是邏輯日誌,根據每行進行記錄。
redo用於實現事務的永續性,有兩個部分組成,一是記憶體中重做日誌緩衝,二是重做日誌檔案。
innodb通過ForceLogatCommit機制實現事務的永續性,即當事務提交時,必須將事務的所有日誌寫入到重做日誌檔案持久化。innodb中重做日誌包括redo與undo,redo是順序寫,在資料庫執行時無需對redo進行讀操作,而undo是需要隨機讀寫的。
為確保所有日誌檔案都會寫入日誌檔案,在將重做日誌快取寫入重做日誌檔案中後,innodb需要呼叫一次fsync操作。日誌快取會先寫入到檔案快取中,再進行一次fsync操作,而fsync效率取決於磁碟的效能。
當然重做日誌在事務提交時也可不寫入日誌檔案,而是等待一定時間週期後再執行fsync,由於非強制故會導致宕機時資料丟失。
引數innodb_flush_log_at_trx_commit控制重做日誌重新整理到磁碟的策略,預設為1;為0則提交不寫入重做日誌檔案,僅在masterThread中有;為2則事務提交時寫入重做日誌檔案但是僅寫入檔案系統快取,不進行fsync操作。
binlog與redolog
binlog主要用於資料庫POINT-IN-TIME的恢復以及主從複製
redo主要是儲存引擎層產生,而binlog是資料庫層產生,任何儲存引擎對於資料庫的改動都會產生,記錄的是邏輯日誌,是對應的SQL語句,且只在資料庫事務提交後進行寫入。而redo則是物理日誌,是對頁的操作記錄,在事務進行過程中不斷寫入。
binlog與每個事務一一對應,而redo是一個事務對應多個日誌,且事務的redo寫入時併發的,故其在檔案中記錄的順序並非事務開始的順序。
2.logblock
重做日誌都是以塊的形式儲存,大小512B
3.格式
LSN:logsequencenumber,代表日誌的序列號,innodb中LSN佔用8B,表示含義有:
1.redo寫入總量 2.Checkpoint位置 3.頁的版本
LSN表示事務寫入redo的位元組總量
4.恢復
checkpoint表示已經重新整理到磁碟上的LSN,因此在恢復過程中僅需恢復Checkpoint開始的日誌部分,如上圖,僅需恢復10000-13000之間部分日誌。
三.undo
1.用於資料庫回滾,存放在資料庫內部的特殊段中,稱為undo段,位於共享表空間。
undo是邏輯日誌,只是將資料庫邏輯上恢復到原來的狀態,所有修改邏輯上被取消,但是資料結構與頁本身在回滾前後可能不同。
另一個作用是MVCC
2.undo儲存管理
rollback segment記錄1024個undologsegment,在每個undo log segment中進行undo頁的申請
事務在undologsegment分配頁並寫入undolog時同樣需要寫入重做日誌。事務提交時,innodb將:1.將undolog放入列表中,以供後續purge 2.判斷undolog所在頁是否可重用。
事務提交後並不會立即刪除undolog與其所在頁,以防其他事務需要使用。事務提交時將undolog放入連結串列中,是否可以刪除最終由purge執行緒來判斷。
判斷undo頁使用空間是否小於3/4,若是則表示該undo頁可以被重用,之後新的undo記錄會加在其後。
分為insertundo log與updateundolog
delete操作並不會直接刪除記錄,而是將記錄標記為已刪除(delete flag設定為1),而最終的刪除由purge操作完成。
3.purge
用於完成delete與update操作,這樣設計是因為MVCC
innodb中的historylist根據事務提交順序將undolog進行連結,先提交的事務在末尾。
一個undopage可以存放多個不同事務的undo log。
執行purge時,從historylist中找第一個需要被清理的記錄,為tx1,接著innodb會在undolog所在頁中繼續尋找是否可以繼續被清理的記錄,為tx3與之後的tx5,但是tx5被事務佔用,不能清理,故再次到historylist中尋找,此時為tx2,同理清理完tx2,tx6,tx4,此時undopage2中所有頁都被清理,可以被重用。
先從history list中找undolog再從undopage中找undolog是為了避免大量隨機讀取操作,提高purge效率
可通過innodb_purge_batch_size設定每次purge的undopage數量
4.groupcommit
對於非只讀事務,每次提交時都需進行fsync操作,但是易受限於磁碟的效能,當前資料庫採用groupcommit,即一次fsync,多個事務日誌寫入檔案,以提高效能。
MySQL5.6採用BLGC以解決之前開啟二進位制日誌後,groupcommit失效的問題。
原理如下:
事務提交時,首先按照順序將其放入佇列中,佇列中第一個事務稱為leader,其他稱為follower,leader控制follower的行為,BLGC分為下述三個步驟
1.flush:將每個事務的二進位制日誌寫入到記憶體中;
2.sync:將記憶體中二進位制日誌重新整理到磁碟,若佇列中有多個事務,則依次fsync完成二進位制日誌的寫入;
3.commit:leader根據順序呼叫儲存引擎層的事務的提交