MySQL 8.4 支持原子数据定义语言 (DDL) 语句。此功能称为原子 DDL。原子 DDL 语句将与 DDL 操作关联的数据字典更新、存储引擎操作和二进制日志写入组合到单个原子操作中。该操作要么提交,并将适用的更改持久化到数据字典、存储引擎和二进制日志中,要么回滚,即使服务器在操作期间停止也是如此。
原子 DDL 不是事务性 DDL。DDL 语句(原子性或其他)隐式结束当前会话中处于活动状态的任何事务,就好像您在执行该语句之前执行了 COMMIT
一样。这意味着 DDL 语句不能在另一个事务中执行,不能在事务控制语句(例如 START TRANSACTION ... COMMIT
)中执行,也不能与同一事务中的其他语句组合使用。
MySQL 数据字典提供了集中式事务性元数据存储,从而使原子 DDL 成为可能。
本节以下主题介绍了原子 DDL 功能:
原子 DDL 功能支持表和非表 DDL 语句。与表相关的 DDL 操作需要存储引擎支持,而非表 DDL 操作则不需要。目前,只有 InnoDB
存储引擎支持原子 DDL。
支持的表 DDL 语句包括用于数据库、表空间、表和索引的
CREATE
、ALTER
和DROP
语句,以及TRUNCATE TABLE
语句。支持的非表 DDL 语句包括:
原子 DDL 功能不支持以下语句:
涉及
InnoDB
以外的存储引擎的与表相关的 DDL 语句。
原子 DDL 语句的特性包括以下内容:
元数据更新、二进制日志写入和存储引擎操作(如果适用)组合成单个原子操作。
在 DDL 操作期间,SQL 层没有中间提交。
在适用的情况下:
数据字典、例程、事件和可加载函数缓存的状态与 DDL 操作的状态一致,这意味着缓存会更新以反映 DDL 操作是成功完成还是回滚。
DDL 操作中涉及的存储引擎方法不执行中间提交,并且存储引擎将自身注册为 DDL 操作的一部分。
存储引擎支持 DDL 操作的重做和回滚,这在 DDL 操作的“*后 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 操作。诸如 ALTER TABLE
之类的 DDL 操作可以在“*提交*”阶段之前多次执行“*准备*”和“*执行*”阶段。
*准备*:创建所需的对象并将 DDL 日志写入
mysql.innodb_ddl_log
表。DDL 日志定义了如何前滚和回滚 DDL 操作。*执行*:执行 DDL 操作。例如,为
CREATE TABLE
操作执行创建例程。*提交*:更新数据字典并提交数据字典事务。
*后 DDL*:从
mysql.innodb_ddl_log
表中重放和删除 DDL 日志。为了确保可以安全地执行回滚而不会导致不一致,文件操作(例如重命名或删除数据文件)在此最终阶段执行。此阶段还会从mysql.innodb_dynamic_metadata
数据字典表中删除动态元数据,用于DROP TABLE
、TRUNCATE TABLE
和其他重建表的 DDL 操作。
在“*后 DDL*”阶段,无论 DDL 操作是提交还是回滚,都会从 mysql.innodb_ddl_log
表中重放和删除 DDL 日志。仅当服务器在 DDL 操作期间停止时,DDL 日志才应保留在 mysql.innodb_ddl_log
表中。在这种情况下,DDL 日志将在恢复后重放和删除。
在恢复情况下,当服务器重新启动时,DDL 操作可能会提交或回滚。如果在 DDL 操作的“*提交*”阶段执行的数据字典事务出现在重做日志和二进制日志中,则该操作被视为成功并被前滚。否则,当 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.innodb_ddl_log
表无法在非调试版本的 MySQL 中直接访问。(请参阅第 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