MySQL 9.0 支持原子数据定义语言 (DDL) 语句。此功能称为原子 DDL。原子 DDL 语句将与 DDL 操作相关的数据字典更新、存储引擎操作和二进制日志写入合并到单个原子操作中。该操作要么被提交,并将适用的更改持久化到数据字典、存储引擎和二进制日志中,要么被回滚,即使服务器在操作期间停止也是如此。
原子 DDL 不是事务性 DDL。DDL 语句,无论是原子的还是其他的,都会隐式结束当前会话中处于活动状态的任何事务,就像您在执行语句之前执行了 COMMIT
一样。这意味着不能在另一个事务中、在事务控制语句(如 START TRANSACTION ... COMMIT
)中执行 DDL 语句,也不能将 DDL 语句与同一事务中的其他语句组合在一起。
原子 DDL 是由 MySQL 数据字典实现的,该字典提供集中的、事务性的元数据存储。
本节以下主题介绍了原子 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 操作。DDL 操作(如 ALTER TABLE
)可以在提交阶段之前多次执行准备和执行阶段。
准备:创建所需的对象并将 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