MySQL 8.3 支持原子数据定义语言(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 特性:
-
与存储引擎无关的表相关 DDL 语句,除
InnoDB外。
原子 DDL 语句的特性包括以下几点:
-
元数据更新、binary log 写入和存储引擎操作(如果适用),将合并到单个原子操作中。
-
在 DDL 操作期间,不会在 SQL 层面进行中间提交。
-
如果适用:
-
数据字典、routine、事件和可加载函数缓存的状态将与 DDL 操作的状态保持一致,即缓存将更新以反映 DDL 操作是否成功完成或回滚。
-
存储引擎方法在 DDL 操作中不执行中间提交,并将自己注册为 DDL 操作的一部分。
-
存储引擎支持 DDL 操作的 redo 和回滚,在 DDL 操作的 Post-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 日志写入
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 阶段重放和删除,ardless of whether the DDL 操作 is committed or rolled back。DDL 日志应该只在服务器在 DDL 操作期间崩溃时留在 mysql.innodb_ddl_log 表中。在这种情况下,DDL 日志将在恢复后重放和删除。
在恢复情况下,DDL 操作可能在服务器重新启动时提交或回滚。如果在 DDL 操作的 提交 阶段执行的数据字典事务出现在 redo 日志和二进制日志中,则该操作被认为是成功的,并将其回滚。否则,在 InnoDB 回放数据字典 redo 日志时,未完成的数据字典事务将被回滚,DDL 操作将被回滚。
要查看在原子 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 以查看写入 stderr 的 DDL 日志,用于 CREATE TABLE 操作。
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