Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

MySQL 8.3 Reference Manual  /  ...  /  Atomic Data Definition Statement Support

15.1.1 原子数据定义语句支持

MySQL 8.3 支持原子数据定义语言(DDL)语句。这项功能被称为 原子 DDL。一个原子 DDL 语句将数据字典更新、存储引擎操作和二进制日志写入结合到一个单一的、原子的操作中。该操作要么提交,相关的更改被持久化到数据字典、存储引擎和二进制日志中,要么回滚,即使服务器在操作过程中停止。

Note

原子 DDL 不是 事务性 DDL。DDL 语句,无论是原子的还是其他的,隐式地结束当前会话中的任何事务,就像您执行了一个 COMMIT 之前执行该语句一样。这意味着 DDL 语句不能在另一个事务中执行,也不能在事务控制语句中执行,例如 START TRANSACTION ... COMMIT,或与其他语句组合在同一个事务中。

原子 DDL 是由 MySQL 数据字典提供的,提供了集中式、事务性的元数据存储。

原子 DDL 功能在本节的以下主题中进行了描述:

支持的 DDL 语句

原子 DDL 功能支持表和非表 DDL 语句。表相关的 DDL 操作需要存储引擎支持,而非表 DDL 操作不需要。目前,只有 InnoDB 存储引擎支持原子 DDL。

  • 支持的表 DDL 语句包括 CREATEALTERDROP 语句,用于数据库、表空间、表和索引,以及 TRUNCATE TABLE 语句。

  • 支持的非表 DDL 语句包括:

    • CREATEDROP 语句,以及,如果适用,ALTER 语句,用于存储过程、触发器、视图和可加载函数。

    • 账户管理语句:CREATEALTERDROP,以及如果适用,RENAME 语句用于用户和角色,以及GRANTREVOKE 语句。

以下语句不支持原子 DDL 特性:

原子 DDL 特性

原子 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 日志

Note

mysql.innodb_ddl_log 表的更改的重做日志将立即刷新到磁盘,而不管 innodb_flush_log_at_trx_commit 设置如何。立即刷新重做日志避免了数据文件被 DDL 操作修改,但 mysql.innodb_ddl_log 表的重做日志未被持久化到磁盘的情况,这可能会在回滚或恢复期间引发错误。

InnoDB 存储引擎将 DDL 操作执行为多个阶段。例如,ALTER TABLE 操作可能会在提交阶段之前多次执行 准备执行 阶段。

  1. 准备:创建所需对象并将 DDL 日志写入 mysql.innodb_ddl_log 表。DDL 日志定义如何向前和回滚 DDL 操作。

  2. 执行:执行 DDL 操作。例如,对于 CREATE TABLE 操作,执行创建例程。

  3. 提交:更新数据字典并提交数据字典事务。

  4. 后 DDL:重放和删除 mysql.innodb_ddl_log 表中的 DDL 日志。为了确保回滚可以安全地执行而不引入不一致,文件操作例如重命名或删除数据文件将在此最终阶段执行。此阶段还删除了 mysql.innodb_dynamic_metadata 数据字典表中的动态元数据,用于 DROP TABLETRUNCATE 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 日志

要查看在原子 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