1. 程式人生 > 實用技巧 >MySQL技術內幕Chapter7事務

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根據順序呼叫儲存引擎層的事務的提交