文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (美式信紙) - 39.9Mb
PDF (A4) - 40.0Mb
Man Pages (TGZ) - 258.5Kb
Man Pages (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


17.6.5 重做日誌

重做日誌是一種基於磁碟的資料結構,用於在當機復原期間更正由未完成交易寫入的資料。在正常操作期間,重做日誌會編碼因 SQL 陳述式或低階 API 呼叫而產生的資料表資料變更要求。在意外關機之前未完成更新資料檔案的修改會在初始化期間以及接受連線之前自動重播。有關重做日誌在當機復原中的作用的資訊,請參閱第 17.18.2 節,「InnoDB 復原」

重做日誌在磁碟上以重做日誌檔案表示。寫入重做日誌檔案的資料會根據受影響的記錄進行編碼,而此資料統稱為重做。資料通過重做日誌檔案的過程由不斷增加的LSN 值表示。重做日誌資料會在資料修改發生時附加,並且最舊的資料會在檢查點進度時截斷。

有關重做日誌的資訊和程序在以下章節中說明

設定重做日誌容量

innodb_redo_log_capacity系統變數控制重做日誌檔案佔用的磁碟空間量。您可以使用選項檔案在啟動時或使用 SET GLOBAL 陳述式在執行階段設定此變數;例如,以下陳述式將重做日誌容量設定為 8GB

SET GLOBAL innodb_redo_log_capacity = 8589934592;

當在執行階段設定時,組態變更會立即發生,但新限制可能需要一些時間才能完全實施。如果重做日誌檔案佔用的空間小於指定的值,則緩衝池中的髒頁將較不積極地從緩衝池刷新到表格空間資料檔案,最終會增加重做日誌檔案佔用的磁碟空間。如果重做日誌檔案佔用的空間大於指定的值,則會更積極地刷新髒頁,最終減少重做日誌檔案佔用的磁碟空間。

如果未定義 innodb_redo_log_capacity,且未定義 innodb_log_file_sizeinnodb_log_files_in_group,則會使用預設的 innodb_redo_log_capacity 值。

如果未定義 innodb_redo_log_capacity,且已定義 innodb_log_file_size 和/或 innodb_log_files_in_group,則 InnoDB 重做日誌容量的計算方式為 (innodb_log_files_in_group * innodb_log_file_size)。此計算不會修改未使用的 innodb_redo_log_capacity 設定的值。

Innodb_redo_log_capacity_resized 伺服器狀態變數表示所有重做日誌檔案的總重做日誌容量。

除非由 innodb_log_group_home_dir 變數指定了不同的目錄,否則重做日誌檔案會位於資料目錄中的 #innodb_redo 目錄中。如果已定義 innodb_log_group_home_dir,則重做日誌檔案會位於該目錄中的 #innodb_redo 目錄中。重做日誌檔案有兩種型別,普通型和備用型。普通重做日誌檔案是正在使用的檔案。備用重做日誌檔案是等待使用的檔案。InnoDB 嘗試維護總共 32 個重做日誌檔案,每個檔案的大小等於 1/32 * innodb_redo_log_capacity;但是,在修改 innodb_redo_log_capacity 設定後,檔案大小可能會暫時有所不同。

重做日誌檔案使用 #ib_redoN 的命名慣例,其中 N 是重做日誌檔案編號。備用重做日誌檔案以 _tmp 後綴表示。以下範例顯示 #innodb_redo 目錄中的重做日誌檔案,其中有 21 個活動重做日誌檔案和 11 個備用重做日誌檔案,依序編號。

'#ib_redo582'  '#ib_redo590'  '#ib_redo598'      '#ib_redo606_tmp'
'#ib_redo583'  '#ib_redo591'  '#ib_redo599'      '#ib_redo607_tmp'
'#ib_redo584'  '#ib_redo592'  '#ib_redo600'      '#ib_redo608_tmp'
'#ib_redo585'  '#ib_redo593'  '#ib_redo601'      '#ib_redo609_tmp'
'#ib_redo586'  '#ib_redo594'  '#ib_redo602'      '#ib_redo610_tmp'
'#ib_redo587'  '#ib_redo595'  '#ib_redo603_tmp'  '#ib_redo611_tmp'
'#ib_redo588'  '#ib_redo596'  '#ib_redo604_tmp'  '#ib_redo612_tmp'
'#ib_redo589'  '#ib_redo597'  '#ib_redo605_tmp'  '#ib_redo613_tmp'

每個普通重做日誌檔案都與特定的 LSN 值範圍相關聯;例如,以下查詢顯示先前範例中列出的活動重做日誌檔案的 START_LSNEND_LSN

mysql> SELECT FILE_NAME, START_LSN, END_LSN FROM performance_schema.innodb_redo_log_files;
+----------------------------+--------------+--------------+
| FILE_NAME                  | START_LSN    | END_LSN      |
+----------------------------+--------------+--------------+
| ./#innodb_redo/#ib_redo582 | 117654982144 | 117658256896 |
| ./#innodb_redo/#ib_redo583 | 117658256896 | 117661531648 |
| ./#innodb_redo/#ib_redo584 | 117661531648 | 117664806400 |
| ./#innodb_redo/#ib_redo585 | 117664806400 | 117668081152 |
| ./#innodb_redo/#ib_redo586 | 117668081152 | 117671355904 |
| ./#innodb_redo/#ib_redo587 | 117671355904 | 117674630656 |
| ./#innodb_redo/#ib_redo588 | 117674630656 | 117677905408 |
| ./#innodb_redo/#ib_redo589 | 117677905408 | 117681180160 |
| ./#innodb_redo/#ib_redo590 | 117681180160 | 117684454912 |
| ./#innodb_redo/#ib_redo591 | 117684454912 | 117687729664 |
| ./#innodb_redo/#ib_redo592 | 117687729664 | 117691004416 |
| ./#innodb_redo/#ib_redo593 | 117691004416 | 117694279168 |
| ./#innodb_redo/#ib_redo594 | 117694279168 | 117697553920 |
| ./#innodb_redo/#ib_redo595 | 117697553920 | 117700828672 |
| ./#innodb_redo/#ib_redo596 | 117700828672 | 117704103424 |
| ./#innodb_redo/#ib_redo597 | 117704103424 | 117707378176 |
| ./#innodb_redo/#ib_redo598 | 117707378176 | 117710652928 |
| ./#innodb_redo/#ib_redo599 | 117710652928 | 117713927680 |
| ./#innodb_redo/#ib_redo600 | 117713927680 | 117717202432 |
| ./#innodb_redo/#ib_redo601 | 117717202432 | 117720477184 |
| ./#innodb_redo/#ib_redo602 | 117720477184 | 117723751936 |
+----------------------------+--------------+--------------+

在執行檢查點時,InnoDB 會將檢查點 LSN 儲存在包含此 LSN 的檔案標頭中。在復原期間,會檢查所有重做日誌檔案,並從最新的檢查點 LSN 開始復原。

提供了數個狀態變數來監控重做日誌和重做日誌容量調整大小作業;例如,您可以查詢 Innodb_redo_log_resize_status 以檢視調整大小作業的狀態

mysql> SHOW STATUS LIKE 'Innodb_redo_log_resize_status';
+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| Innodb_redo_log_resize_status | OK    |
+-------------------------------+-------+

Innodb_redo_log_capacity_resized 狀態變數會顯示目前的重做日誌容量限制

mysql> SHOW STATUS LIKE 'Innodb_redo_log_capacity_resized';
 +----------------------------------+-----------+
| Variable_name                    | Value     |
+----------------------------------+-----------+
| Innodb_redo_log_capacity_resized | 104857600 |
+----------------------------------+-----------+

其他適用的狀態變數包括

有關更多資訊,請參閱狀態變數描述。

您可以透過查詢 innodb_redo_log_files Performance Schema 表格,來檢視有關活動重做日誌檔案的資訊。以下查詢會從表格的所有欄位中擷取資料

SELECT FILE_ID, START_LSN, END_LSN, SIZE_IN_BYTES, IS_FULL, CONSUMER_LEVEL 
FROM performance_schema.innodb_redo_log_files;

自動重做日誌容量組態

啟用 innodb_dedicated_server 時,InnoDB 會自動組態某些 InnoDB 參數,包括重做日誌容量。自動組態適用於位於專用於 MySQL 的伺服器上的 MySQL 執行個體,其中 MySQL 伺服器可以使用所有可用的系統資源。有關更多資訊,請參閱 第 17.8.12 節,「為專用 MySQL 伺服器啟用自動組態」

重做日誌封存

複製重做日誌記錄的備份公用程式有時可能無法跟上備份作業進行期間重做日誌的產生速度,導致重做日誌記錄因被覆寫而遺失。當備份作業期間有大量的 MySQL 伺服器活動,且重做日誌檔案儲存媒體的運作速度快於備份儲存媒體時,最常發生此問題。重做日誌封存功能可解決此問題,它會將重做日誌記錄循序寫入封存檔案,並寫入重做日誌檔案。備份公用程式可以根據需要從封存檔案複製重做日誌記錄,從而避免潛在的資料遺失。

如果在伺服器上設定了重做日誌封存,MySQL Enterprise Backup (隨附於 MySQL Enterprise Edition) 會在備份 MySQL 伺服器時使用重做日誌封存功能。

在伺服器上啟用重做日誌封存需要為 innodb_redo_log_archive_dirs 系統變數設定值。該值指定為以分號分隔的標籤重做日誌封存目錄清單。 label:directory 配對以冒號 (:) 分隔。例如

mysql> SET GLOBAL innodb_redo_log_archive_dirs='label1:directory_path1[;label2:directory_path2;…]';

label 是封存目錄的任意識別碼。它可以是任何字元字串,但冒號 (:) 除外,冒號是不允許的。也允許使用空白標籤,但在此情況下仍需要冒號 (:)。必須指定 directory_path。選取用於重做日誌封存檔案的目錄必須在啟用重做日誌封存時存在,否則會傳回錯誤。路徑可以包含冒號 (':'),但不允許分號 (;)。

必須先組態 innodb_redo_log_archive_dirs 變數,才能啟用重做日誌封存。預設值為 NULL,這不允許啟用重做日誌封存。

注意事項

您指定的封存目錄必須符合下列要求。(啟用重做日誌封存時會強制執行這些要求。)

  • 目錄必須存在。重做日誌封存程序不會建立目錄。否則,會傳回下列錯誤

    ERROR 3844 (HY000): 重做日誌封存目錄 'directory_path1' 不存在或不是目錄

  • 目錄不得可供世界存取。這是為了防止重做日誌資料暴露給系統上未經授權的使用者。否則,會傳回下列錯誤

    ERROR 3846 (HY000): 所有作業系統使用者都可存取重做日誌封存目錄 'directory_path1'

  • 目錄不能是由 datadirinnodb_data_home_dirinnodb_directoriesinnodb_log_group_home_dirinnodb_temp_tablespaces_dirinnodb_tmpdirinnodb_undo_directorysecure_file_priv 定義的目錄,它們也不能是這些目錄的父目錄或子目錄。否則,會傳回類似於以下的錯誤

    ERROR 3845 (HY000): 重做日誌封存目錄 'directory_path1' 位於伺服器目錄 'datadir' - '/path/to/data_directory' 中、之下或之上

當支援重做日誌封存的備份公用程式啟動備份時,備份公用程式會透過叫用 innodb_redo_log_archive_start() 函數來啟動重做日誌封存。

如果您未使用支援重做日誌封存的備份公用程式,也可以手動啟動重做日誌封存,如下所示

mysql> SELECT innodb_redo_log_archive_start('label', 'subdir');
+------------------------------------------+
| innodb_redo_log_archive_start('label') |
+------------------------------------------+
| 0                                        |
+------------------------------------------+

mysql> DO innodb_redo_log_archive_start('label', 'subdir');
Query OK, 0 rows affected (0.09 sec)
請注意

啟動重做日誌封存的 MySQL 工作階段 (使用 innodb_redo_log_archive_start()) 必須在封存期間保持開啟。相同的工作階段必須停用重做日誌封存 (使用 innodb_redo_log_archive_stop())。如果工作階段在明確停用重做日誌封存之前終止,則伺服器會隱含地停用重做日誌封存並移除重做日誌封存檔案。

其中 label 是由 innodb_redo_log_archive_dirs 定義的標籤;subdir 是選擇性引數,用於指定由 label 識別的目錄的子目錄,以儲存封存檔案;它必須是簡單的目錄名稱 (不允許使用斜線 (/)、反斜線 (\) 或冒號 (:))。subdir 可以是空的、Null 或省略。

只有擁有 INNODB_REDO_LOG_ARCHIVE 權限的使用者才能透過叫用 innodb_redo_log_archive_start() 來啟動重做日誌封存,或使用 innodb_redo_log_archive_stop() 來停用它。執行備份公用程式的 MySQL 使用者或手動啟動和停用重做日誌封存的 MySQL 使用者必須擁有此權限。

重做日誌封存檔案路徑為 directory_identified_by_label/[subdir/]archive.serverUUID.000001.log,其中 directory_identified_by_label 是由 innodb_redo_log_archive_start()label 引數識別的封存目錄。subdir 是用於 innodb_redo_log_archive_start() 的選擇性引數。

例如,重做日誌封存檔案的完整路徑和名稱如下所示

/directory_path/subdirectory/archive.e71a47dc-61f8-11e9-a3cb-080027154b4d.000001.log

在備份公用程式完成複製 InnoDB 資料檔案後,它會透過呼叫 innodb_redo_log_archive_stop() 函數來停用重做日誌封存。

如果您未使用支援重做日誌封存的備份公用程式,也可以手動停用重做日誌封存,如下所示

mysql> SELECT innodb_redo_log_archive_stop();
+--------------------------------+
| innodb_redo_log_archive_stop() |
+--------------------------------+
| 0                              |
+--------------------------------+

mysql> DO innodb_redo_log_archive_stop();
Query OK, 0 rows affected (0.01 sec)

在停止函數成功完成後,備份公用程式會從封存檔案中尋找重做日誌資料的相關區段,並將其複製到備份中。

在備份公用程式完成複製重做日誌資料且不再需要重做日誌封存檔案後,它會刪除封存檔案。

在正常情況下,移除封存檔案是備份公用程式的責任。但是,如果在呼叫 innodb_redo_log_archive_stop() 之前重做日誌封存作業意外終止,MySQL 伺服器會移除檔案。

效能考量

由於額外的寫入活動,啟動重做日誌封存通常會產生輕微的效能成本。

在 Unix 和類 Unix 作業系統上,假設沒有持續的高更新速率,則效能影響通常很小。在 Windows 上,假設相同情況,則效能影響通常會稍高一些。

如果存在持續的高更新速率,且重做日誌封存檔案與重做日誌檔案位於相同的儲存媒體上,則由於複合寫入活動,效能影響可能會更顯著。

如果更新率持續偏高,且重做日誌封存檔位於比重做日誌檔更慢的儲存媒體上,效能將會受到任意程度的影響。

除非重做日誌封存檔的儲存媒體運作速度遠慢於重做日誌檔的儲存媒體,且有大量持久化的重做日誌區塊等待寫入重做日誌封存檔,否則寫入重做日誌封存檔不會妨礙正常的交易日誌記錄。在這種情況下,交易日誌記錄的速率會降低到較慢的重做日誌封存檔所在儲存媒體可以管理的程度。

停用重做日誌記錄

您可以使用 ALTER INSTANCE DISABLE INNODB REDO_LOG 陳述式停用重做日誌記錄。此功能旨在將資料載入新的 MySQL 執行個體。停用重做日誌記錄可避免重做日誌寫入和雙寫緩衝,從而加快資料載入速度。

警告

此功能僅適用於將資料載入新的 MySQL 執行個體。請勿在生產系統上停用重做日誌記錄。 允許在停用重做日誌記錄時關閉並重新啟動伺服器,但若在停用重做日誌記錄時發生意外的伺服器停止,可能會導致資料遺失和執行個體損毀。

如果在停用重做日誌記錄時發生意外的伺服器停止後嘗試重新啟動伺服器,將會被拒絕並顯示以下錯誤:

[ERROR] [MY-013598] [InnoDB] Server was killed when Innodb Redo 
logging was disabled. Data files could be corrupt. You can try 
to restart the database with innodb_force_recovery=6

在這種情況下,請初始化一個新的 MySQL 執行個體並重新開始資料載入程序。

啟用和停用重做日誌記錄需要 INNODB_REDO_LOG_ENABLE 權限。

可以使用 Innodb_redo_log_enabled 狀態變數監控重做日誌記錄的狀態。

在停用重做日誌記錄時,不允許執行複製操作和重做日誌封存,反之亦然。

ALTER INSTANCE [ENABLE|DISABLE] INNODB REDO_LOG 操作需要獨佔備份中繼資料鎖定,這會防止其他 ALTER INSTANCE 操作同時執行。其他 ALTER INSTANCE 操作必須等待鎖定釋放後才能執行。

以下程序示範如何在將資料載入新的 MySQL 執行個體時停用重做日誌記錄。

  1. 在新的 MySQL 執行個體上,授予負責停用重做日誌記錄的使用者帳戶 INNODB_REDO_LOG_ENABLE 權限。

    mysql> GRANT INNODB_REDO_LOG_ENABLE ON *.* to 'data_load_admin';
  2. data_load_admin 使用者身分停用重做日誌記錄

    mysql> ALTER INSTANCE DISABLE INNODB REDO_LOG;
  3. 檢查 Innodb_redo_log_enabled 狀態變數,以確保重做日誌記錄已停用。

    mysql> SHOW GLOBAL STATUS LIKE 'Innodb_redo_log_enabled';
    +-------------------------+-------+
    | Variable_name           | Value |
    +-------------------------+-------+
    | Innodb_redo_log_enabled | OFF   |
    +-------------------------+-------+
  4. 執行資料載入操作。

  5. 在資料載入操作完成後,以 data_load_admin 使用者身分啟用重做日誌記錄

    mysql> ALTER INSTANCE ENABLE INNODB REDO_LOG;
  6. 檢查 Innodb_redo_log_enabled 狀態變數,以確保重做日誌記錄已啟用。

    mysql> SHOW GLOBAL STATUS LIKE 'Innodb_redo_log_enabled';
    +-------------------------+-------+
    | Variable_name           | Value |
    +-------------------------+-------+
    | Innodb_redo_log_enabled | ON    |
    +-------------------------+-------+