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