MySQL 9.0 支援原子資料定義語言 (DDL) 語句。此功能稱為原子 DDL。原子 DDL 語句將與 DDL 操作相關的資料字典更新、儲存引擎操作和二進制日誌寫入組合為單一的原子操作。該操作會被提交,並將適用的變更保存到資料字典、儲存引擎和二進制日誌,或者會被回滾,即使伺服器在操作過程中停止。
原子 DDL 不是交易式 DDL。 DDL 語句,無論是否為原子語句,都會隱式地結束目前工作階段中任何活動的交易,就像您在執行語句之前執行了COMMIT
一樣。這表示 DDL 語句無法在其他交易內執行,也無法在交易控制語句(例如 START TRANSACTION ... COMMIT
)內執行,或與同一交易中的其他語句組合。
原子 DDL 是透過 MySQL 資料字典實現的,該字典提供集中的交易式元資料儲存。
原子 DDL 功能在本節的以下主題中說明
原子 DDL 功能支援表格和非表格 DDL 陳述式。與表格相關的 DDL 操作需要儲存引擎支援,而與非表格相關的 DDL 操作則不需要。目前,只有 InnoDB
儲存引擎支援原子 DDL。
支援的表格 DDL 陳述式包括資料庫、表格空間、表格和索引的
CREATE
、ALTER
和DROP
陳述式,以及TRUNCATE TABLE
陳述式。支援的非表格 DDL 陳述式包括
下列陳述式不支援原子 DDL 功能
涉及
InnoDB
以外的儲存引擎的與表格相關的 DDL 陳述式。INSTALL PLUGIN
和UNINSTALL PLUGIN
陳述式。CREATE SERVER
、ALTER SERVER
和DROP SERVER
陳述式。
原子 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 記錄。
對 mysql.innodb_ddl_log
資料表所做的變更的重做記錄會立即刷新到磁碟,無論 innodb_flush_log_at_trx_commit
設定為何。立即刷新重做記錄可避免因 DDL 操作而修改資料檔案,但對 mysql.innodb_ddl_log
資料表所做的變更的重做記錄並未持續保存到磁碟的情況。這種情況可能會在復原或還原期間造成錯誤。
InnoDB
儲存引擎會分階段執行 DDL 操作。在 Commit 階段之前,ALTER TABLE
等 DDL 操作可能會多次執行 Prepare 和 Perform 階段。
Prepare:建立必要的物件,並將 DDL 記錄寫入
mysql.innodb_ddl_log
資料表。DDL 記錄定義如何向前復原和向後復原 DDL 操作。Perform:執行 DDL 操作。例如,針對
CREATE TABLE
操作執行建立常式。Commit:更新資料字典並認可資料字典交易。
Post-DDL:從
mysql.innodb_ddl_log
資料表中重播並移除 DDL 記錄。為了確保在不引入不一致的情況下安全地執行復原,在此最後階段執行檔案操作,例如重新命名或移除資料檔案。此階段也會從mysql.innodb_dynamic_metadata
資料字典表格中移除DROP TABLE
、TRUNCATE TABLE
以及其他重建表格的 DDL 操作的動態中繼資料。
無論 DDL 操作是認可還是復原,DDL 記錄都會在 Post-DDL 階段期間從 mysql.innodb_ddl_log
資料表中重播並移除。如果伺服器在 DDL 操作期間停止,則 DDL 記錄應只保留在 mysql.innodb_ddl_log
資料表中。在此情況下,DDL 記錄會在還原後重播並移除。
在還原情況下,重新啟動伺服器時,可能會認可或復原 DDL 操作。如果在重做記錄和二進位記錄中存在 DDL 操作的 Commit 階段期間執行的資料字典交易,則會將操作視為成功並向前復原。否則,當 InnoDB
重播資料字典重做記錄時,會復原不完整的資料字典交易,並且也會復原 DDL 操作。
若要檢視在涉及 InnoDB
儲存引擎的原子 DDL 操作期間寫入 mysql.innodb_ddl_log
資料字典表格的 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
以檢視為 CREATE TABLE
操作寫入 strderr
的 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