資料庫日誌redo和undo
資料庫的ACID屬性
Atomicity:原子性,以事物transact為最小單位,事物中的所有操作,要麼都執行完,要麼都不執行,不存在一部分操作執行,另一部分操作不執行的情況。
Consistency:一致性,在事物開始和事物完成後,資料庫的完整性限制不會改變。
Isolation:隔離性,同一個資料庫中同時併發執行多個事務,事物之間的操作不會相互影響。
Durability:永續性,事物完成之後,事物所作的操作會持久存在於資料庫中。
Redo log 和undo log
Redo log:由DML(insert delete update)操作,引起的頁面變化,都需要記錄到redo log中,大部分為物理日誌
在頁面修改完成之後,在髒資料由cache寫入到磁碟之前,會寫入redo日誌中。
日誌先行,日誌會先寫入到磁碟中,資料後寫入
聚簇索引/二級索引/undo頁面的修改,均需要記錄在redo日誌中
Redo log是啥?官方文件解釋如下:
Redo log是一個基於磁碟的資料格式,在資料庫災難恢復過程中,用於恢復未完成的事物,修復資料的。在正常的操作過程中,redo log將來自於SQL 語句或者其他API呼叫的請求,轉化為資料表中的變化,當對資料的改變操作還未完成之前,遭遇了意外的停機,那這些變化會在資料庫啟動初始化的過程中進行replay重演,這個重演的過程,是在接受client請求之前,就會完成。
預設情況下,redo log在磁碟上的體現,一般是ib_logfile0和ib_logfile1兩個檔案,mysql以迴圈的方式,寫這兩個檔案,在redo log中的資料,是以記錄變化為編碼,這些日誌資料,也就體現了資料的變化,在log中的一段內容,就體現了一個已經增加的LSN增量。
在mysql的配置檔案中,innodb_log_file_size設定了redo log檔案的大小,innodb_log_file_in_group設定了日誌檔案的個數,這些設定必須重啟才能生效,當innodb檢測到設定的大小和當前的檔案大小不一致時,會設定一個檢查點,然後關閉該日誌檔案,刪除舊檔案,建立一個設定大小的日誌檔案,開始寫入日誌。
Redo log刷盤的組提交
和其他所有相容ACID模型的資料庫引擎一樣,innodb資料引擎也是會在事物提交之前,先將redo log檔案刷盤,而且innodb還使用了一種組提交機制,同時將多個事務的redo log刷到磁碟中,避免一個事物一個提交,通過該組提交機制,一次日誌刷盤操作,會將同時進行的多個事務的redo log提交,提高了中斷效率。
Undo log:由DML 操作導致的資料記錄變化,均需要將變化前的映象,寫入到undo log中,是一種邏輯日誌。
undo log是啥?官方文件解釋如下:
undo log是一組undo log記錄的集合,這些undo log記錄是關於某個事物的,一個undo log記錄中包含了描述如何將最後的更新回退到叢集索引記錄的資訊,如果有某一個事物需要去使用原始資料(比如在一個一致性的讀事物中),這些原始沒有被修改的資料,就會通過undo log記錄進行恢復。Undo log存在於undo log段中,undo log段中包含了回滾段,而回滾段存在於系統表空間、臨時表空間和回滾表空間中。
Innodb支援128個回滾段,其中有32個是為臨時表的事物操作預留的,每一個更新臨時表的事物(不包含只讀事物)會被分配2個回滾段,一個是啟用了redo的回滾段,另一個是沒有啟用redo的回滾段。只讀事物只會分配一個沒有啟用redo的回滾段,因為只讀事物是隻允許修改臨時表的。
剩下的96個回滾段,每一個都支援1023個一致性資料修改事物,所以能夠支援近似於96K的一致性資料修改事物,96K的限制是假設事物不會去修改臨時表,如果所有的資料修改事物都修改了臨時表,這個大小大約是32K。
既然DML操作,會引起redo log和undo log的變化,具體進行分析一下。
Insert 插入操作:
Insert插入操作,不會對原有資料產生影響,只是新產生一條記錄和對應的索引,以前的記錄和索引不會被修改,所以對undo log的要求不高,但是對redo log的要求就比較高了,用於replay,就需要整條插入的所有資訊。
Undo log:記錄insert插入記錄的主鍵值
Redo log:記錄日誌操作頁面(space_id,page_no)、完整的插入記錄、系統列等
Delete刪除操作
Delete刪除操作是要從當前的庫或者表中刪除一部分已經存在的記錄,如果在刪除過程中出現了資料庫的crash,在recovery過程中需要再次進行刪除操作,而recovery中的replay利用的就是redo log,所以redo log中需要記錄刪除的具體資訊,比如主鍵等關鍵資訊;而在undo log中需要記錄的資訊就會更多了,因為有可能在執行刪除事物之前,存在一個一致性的讀事物,需要讀取當前被刪除的這些記錄,所以這些刪除的記錄的原始資料,是要存放在undo log中的;另外,由於讀查詢是會使用到索引等資訊,所以這些索引資訊,也是要存放在undo log中的。所以綜上:
Redo log:記錄日誌操作頁面、刪除記錄的系統列,記錄在頁面中的位置,同時記錄undo page的修改
Undo log:
- Delete操作在innodb中為delete mark操作,並不是真的刪除資料,只是將記錄標記為delete
- 記錄當前刪除記錄的系統列
- 記錄當前刪除記錄的主鍵
- 記錄當前刪除記錄的所有索引
Update操作
Update的操作分為三種情況,對於不同的操作情況,redo log和undo log中記錄的資訊也是不一樣的。
Section 1:未修改索引,修改的屬性列長度不變
在這種update場景中,只是對非索引列的值進行了修改,並未修改該列的長度,所以在redo log中,會進行定點的update,會記錄的是update log;而在undo log中,需要記錄的是update操作的系統列、操作記錄的主鍵、操作記錄該列的原值,如果該update列中包含二級索引,二級索引的原值,也需要記錄到undo log中。綜上:
Redo log:記錄update redo log,如果更新列中包含二級索引,則需要對二級索引進行delete mark操作,然後重新insert一條新的二級索引;同時對undo 頁面的修改,同步也要寫入到redo log中。
Undo log:記錄update的系統列、操作記錄的主鍵、操作記錄該列的原值。如果該update列中包含二級索引,二級索引的原值,也需要記錄到undo log中
Section 2:未修改索引,修改了屬性列長度
這種update場景和section 1中的場景類似,唯一的區別是屬性列長度發生了變化,這中變化,在undo log中記錄的資訊,和section 1中的資訊形同,而redo log中記錄的資訊會發生變化,這個時候記錄的不再是定點的update,應該是先delete原始的資訊,然後insert一條資訊。
undo log:記錄資訊和section 1中的undo log資訊相同
redo log:不能定點的update了,會記錄delete+insert redo log
section 3:修改索引列值
在資料庫中,修改某條記錄的索引列值,實際上的操作是將該記錄delete,然後重新插入一條新的記錄,然後生成索引,更新索引表。在這一連串的操作過程中,redo log實際上是要記錄一個delete和一個insert的redo log,而undo log上是要記錄原始的記錄(delete操作)和insert的操作記錄。
LSN:log sequence number
日誌序列號,遞增產生,一個LSN可以唯一標識一個redo log,其中有一個叫checkpoint LSN,用來標識資料庫crash的redo 起始點,LSN和日誌檔案位置意義對應。