Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


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

15.1.1 原子数据定义语言支持

MySQL 8.4 支持原子数据定义语言(DDL)语句。这一特性称为原子 DDL。原子 DDL 语句将数据字典更新、存储引擎操作和二进制日志写入组合成一个单个的原子操作。如果服务器在执行操作时崩溃,操作将被回滚,相关变化将不被持久化到数据字典、存储引擎和二进制日志中。

Note

原子 DDL 不是事务性 DDL。无论是原子还是非原子,DDL 语句都会隐式地结束当前会话中的活动事务,就像你执行了COMMIT一样。这意味着,DDL 语句不能在另一个事务中执行,也不能与其他语句组合在同一个事务中。

原子 DDL 是由 MySQL 数据字典提供的-centralized、事务性元数据存储所可能的。

本节下面部分介绍了原子 DDL 的相关内容:

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

  • 支持的表DDL语句包括:

  • Supported non-table DDL statements include:

    • CREATEALTERDROP语句,以及TRUNCATE TABLE语句。

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

原子DDL功能不支持的语句:

原子DDL语句的特点包括:

  • 元数据更新、binary日志写入和存储引擎操作(如果适用)被组合成一个原子操作。

  • 在DDL操作过程中,SQL层面没有中间提交。

  • 如果适用:

    • 数据字典、存储程序、事件和可加载函数缓存的状态与DDL操作的状态一致,意味着缓存会更新以反映DDL操作是否成功或回滚。

    • 在DDL操作中涉及到的存储引擎方法不执行中间提交,存储引擎将自己注册为DDL操作的一部分。

    • 存储引擎支持redo和回滚DDL操作,这是在DDL操作的Post-DDL阶段进行的。

  • DDL操作的可见行为是原子性的。

当前,只有InnoDB存储引擎支持原子DDL。不能支持原子DDL的存储引擎除外,执行DDL操作时可能会出现中断或部分完成引起的一致性问题。

为了支持redo和回滚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表的redo日志,总是立即写入磁盘,不管innodb_flush_log_at_trx_commit设置。立即写入redo日志避免了数据文件由DDL操作修改,但对mysql.innodb_ddl_log表的redo日志未持久化到磁盘的情况,这种情况可能会在回滚或恢复时出现错误。

InnoDB存储引擎以阶段执行DDL操作,例如ALTER TABLE可能在PreparePerform阶段重复执行多次,直到Commit阶段。

  1. Prepare:创建必要对象,并将DDL日志写入mysql.innodb_ddl_log表。DDL日志定义如何回滚和恢复DDL操作。

  2. Perform:执行DDL操作,例如创建一个CREATE TABLE操作。

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

  4. Post-DDL:从mysql.innodb_ddl_log表中回放和删除DDL日志。为了确保回滚操作安全地执行,不会引入不一致,文件操作,如重命名或删除数据文件,在这个最后阶段执行。这阶段还将DROP TABLETRUNCATE TABLE等DDL操作重建表的动态元数据从mysql.innodb_dynamic_metadata数据字典表中删除。

Post-DDL阶段,DDL日志将从mysql.innodb_ddl_log表中回放和删除,不管DDL操作是否已提交或回滚。只有在服务器在DDL操作过程中崩溃时,DDL日志才会留存在mysql.innodb_ddl_log表中。在这种情况下,DDL日志将在恢复后回放和删除。

在恢复情况下,DDL操作可能在服务器重启时提交或回滚。如果数据字典事务在DDL操作的Commit阶段存在于redo日志和二进制日志中,则操作被认为是成功的,并且回滚。否则,InnoDB回放数据字典redo日志时,事务回滚,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 表,以支持redo和回滚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 查看DDL日志写入到 strderrCREATE 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