文件首頁
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


MySQL 8.4 參考手冊  /  ...  /  原子資料定義語句支援

15.1.1 原子資料定義語句支援

MySQL 8.4 支援原子資料定義語言 (DDL) 語句。此功能稱為原子 DDL。原子 DDL 語句將與 DDL 操作相關的資料字典更新、儲存引擎操作和二進制日誌寫入結合到單一原子操作中。該操作會被提交,將適用的變更持久化到資料字典、儲存引擎和二進制日誌,或者被回滾,即使伺服器在操作期間停止也是如此。

注意

原子 DDL 不是事務性 DDL。DDL 語句,無論是否為原子,都會隱式結束目前工作階段中任何處於活動狀態的事務,如同在執行語句之前執行了 COMMIT 一樣。這表示 DDL 語句不能在另一個事務中執行,也不能在諸如 START TRANSACTION ... COMMIT 之類的事務控制語句中執行,也不能與同一事務中的其他語句合併使用。

原子性 DDL 得益於 MySQL 資料字典,它提供了集中式的、具交易性的中繼資料儲存。

本節將在以下主題中描述原子性 DDL 功能

支援的 DDL 語法

原子性 DDL 功能同時支援資料表和非資料表的 DDL 語法。與資料表相關的 DDL 操作需要儲存引擎的支援,而與非資料表相關的 DDL 操作則不需要。目前,只有 InnoDB 儲存引擎支援原子性 DDL。

  • 支援的資料表 DDL 語法包括用於資料庫、表空間、資料表和索引的 CREATEALTERDROP 語法,以及 TRUNCATE TABLE 語法。

  • 支援的非資料表 DDL 語法包括

    • 用於預存程式、觸發器、檢視表和可載入函式的 CREATEDROP 語法,以及在適用的情況下,ALTER 語法。

    • 帳號管理語法:用於使用者和角色的 CREATEALTERDROP 語法,以及在適用的情況下,RENAME 語法,以及 GRANTREVOKE 語法。

原子性 DDL 功能不支援以下語法

原子性 DDL 特性

原子性 DDL 語法的特性包括以下內容

  • 中繼資料更新、二進位日誌寫入和儲存引擎操作(如適用)會合併為單一原子性操作。

  • 在 DDL 操作期間,SQL 層沒有中間提交。

  • 如適用

    • 資料字典、常式、事件和可載入函式快取的狀態與 DDL 操作的狀態一致,表示快取會更新以反映 DDL 操作是否成功完成或回滾。

    • DDL 操作中涉及的儲存引擎方法不會執行中間提交,而且儲存引擎會將自身註冊為 DDL 操作的一部分。

    • 儲存引擎支援 DDL 操作的重做和回滾,這會在 DDL 操作的Post-DDL階段執行。

  • DDL 操作的行為在視覺上是原子性的。

儲存引擎支援

目前,只有 InnoDB 儲存引擎支援原子性 DDL。不支援原子性 DDL 的儲存引擎不受 DDL 原子性的約束。涉及不受約束的儲存引擎的 DDL 操作,仍然可能會在操作中斷或僅部分完成時導致不一致的情況發生。

為了支援 DDL 操作的重做和回滾,InnoDB 會將 DDL 紀錄寫入 mysql.innodb_ddl_log 資料表,這是一個隱藏的資料字典資料表,位於 mysql.ibd 資料字典表空間中。

若要檢視在 DDL 操作期間寫入 mysql.innodb_ddl_log 資料表的 DDL 紀錄,請啟用 innodb_print_ddl_logs 設定選項。如需詳細資訊,請參閱檢視 DDL 紀錄

注意

無論 innodb_flush_log_at_trx_commit 設定為何,對 mysql.innodb_ddl_log 資料表的變更所產生的重做日誌都會立即刷新到磁碟。立即刷新重做日誌可避免因 DDL 操作修改資料檔案,但這些操作對 mysql.innodb_ddl_log 資料表所產生的變更重做日誌卻未持續保存到磁碟的情況。這種情況可能會在回滾或復原期間導致錯誤。

InnoDB 儲存引擎會分階段執行 DDL 操作。DDL 操作(例如 ALTER TABLE)可能會在 Commit 階段之前多次執行準備 (Prepare)執行 (Perform)階段。

  1. 準備 (Prepare):建立所需的物件,並將 DDL 紀錄寫入 mysql.innodb_ddl_log 資料表。DDL 紀錄定義了如何向前和向後回滾 DDL 操作。

  2. 執行 (Perform):執行 DDL 操作。例如,針對 CREATE TABLE 操作執行建立常式。

  3. Commit:更新資料字典並提交資料字典交易。

  4. Post-DDL:從 mysql.innodb_ddl_log 資料表重播和移除 DDL 紀錄。為了確保可以安全地執行回滾而不會造成不一致的情況,例如重新命名或移除資料檔案等檔案操作會在此最後階段執行。此階段也會從 mysql.innodb_dynamic_metadata 資料字典資料表中移除動態中繼資料,以用於 DROP TABLETRUNCATE TABLE 和其他會重建資料表的 DDL 操作。

無論 DDL 操作是提交還是回滾,都會在Post-DDL階段期間從 mysql.innodb_ddl_log 資料表重播和移除 DDL 紀錄。只有在伺服器於 DDL 操作期間停止時,DDL 紀錄才會保留在 mysql.innodb_ddl_log 資料表中。在這種情況下,DDL 紀錄會在復原後重播和移除。

在復原情況下,當伺服器重新啟動時,可能會提交或回滾 DDL 操作。如果 DDL 操作的Commit階段期間執行的資料字典交易出現在重做日誌和二進位日誌中,則該操作會被視為成功並向前推進。否則,當 InnoDB 重播資料字典重做日誌時,不完整的資料字典交易將會被回滾,而 DDL 操作也會被回滾。

檢視 DDL 紀錄

若要檢視在原子性 DDL 操作期間寫入 mysql.innodb_ddl_log 資料字典資料表(涉及 InnoDB 儲存引擎)的 DDL 紀錄,請啟用 innodb_print_ddl_logs,讓 MySQL 將 DDL 紀錄寫入 stderr。根據主機作業系統和 MySQL 設定,stderr 可能是錯誤日誌、終端機或主控台視窗。請參閱第 7.4.2.2 節,「預設錯誤日誌目的地設定」

InnoDB 會將 DDL 紀錄寫入 mysql.innodb_ddl_log 資料表,以支援 DDL 操作的重做和回滾。mysql.innodb_ddl_log 資料表是位於 mysql.ibd 資料字典表空間中的隱藏資料字典資料表。與其他隱藏的資料字典資料表類似,在非除錯版本的 MySQL 中無法直接存取 mysql.innodb_ddl_log 資料表。(請參閱第 16.1 節,「資料字典結構描述」。) mysql.innodb_ddl_log 資料表的結構對應於以下定義

CREATE TABLE mysql.innodb_ddl_log (
  id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  thread_id BIGINT UNSIGNED NOT NULL,
  type INT UNSIGNED NOT NULL,
  space_id INT UNSIGNED,
  page_no INT UNSIGNED,
  index_id BIGINT UNSIGNED,
  table_id BIGINT UNSIGNED,
  old_file_path VARCHAR(512) COLLATE utf8mb4_bin,
  new_file_path VARCHAR(512) COLLATE utf8mb4_bin,
  KEY(thread_id)
);
  • id:DDL 紀錄的唯一識別碼。

  • thread_id:每個 DDL 紀錄都會被指派一個 thread_id,用於重播和移除屬於特定 DDL 操作的 DDL 紀錄。涉及多個資料檔案操作的 DDL 操作會產生多個 DDL 紀錄。

  • type:DDL 操作類型。類型包括 FREE (卸載索引樹)、DELETE (刪除檔案)、RENAME (重新命名檔案) 或 DROP (從 mysql.innodb_dynamic_metadata 資料字典資料表卸載中繼資料)。

  • space_id:表空間 ID。

  • page_no:包含配置資訊的頁面;例如索引樹根頁面。

  • index_id:索引 ID。

  • table_id:資料表 ID。

  • old_file_path:舊表空間檔案路徑。由建立或卸載表空間檔案的 DDL 操作所使用;也由重新命名表空間的 DDL 操作所使用。

  • new_file_path:新表空間檔案路徑。由重新命名表空間檔案的 DDL 操作所使用。

此範例示範如何啟用 innodb_print_ddl_logs,以檢視寫入 stderrCREATE TABLE 操作的 DDL 紀錄。

mysql> SET GLOBAL innodb_print_ddl_logs=1;
mysql> CREATE TABLE t1 (c1 INT) ENGINE = InnoDB;
[Note] [000000] InnoDB: DDL log insert : [DDL record: DELETE SPACE, id=18, thread_id=7,
space_id=5, old_file_path=./test/t1.ibd]
[Note] [000000] InnoDB: DDL log delete : by id 18
[Note] [000000] InnoDB: DDL log insert : [DDL record: REMOVE CACHE, id=19, thread_id=7,
table_id=1058, new_file_path=test/t1]
[Note] [000000] InnoDB: DDL log delete : by id 19
[Note] [000000] InnoDB: DDL log insert : [DDL record: FREE, id=20, thread_id=7,
space_id=5, index_id=132, page_no=4]
[Note] [000000] InnoDB: DDL log delete : by id 20
[Note] [000000] InnoDB: DDL log post ddl : begin for thread id : 7
[Note] [000000] InnoDB: DDL log post ddl : end for thread id : 7