10bet网址
MySQL 8.0参考手册
相关的文档10bet官方网站 本手册下载
PDF (Ltr)- 41.6 mb
PDF (A4)- 41.7 mb
手册页(TGZ)- 262.5 kb
手册页(邮政编码)- 372.6 kb
信息(Gzip)- 4.0 mb
信息(邮政编码)- 4.0 mb
本手册节选

MySQL 8.0参考手册/.../ 原子数据定义语句支持

13.1.1原子数据定义语句支持

MySQL 8.0支持原子数据定义语言(DDL)语句。这个特性被称为原子DDL.原子DDL语句将与DDL操作相关的数据字典更新、存储引擎操作和二进制日志写入组合成单个的原子操作。将提交操作,并将适用的更改持久化到数据字典、存储引擎和二进制日志,或者回滚操作,即使在操作期间服务器停止。

请注意

原子DDL不是事务性的DDL.DDL语句(原子的或其他形式的)隐式地结束当前会话中活动的任何事务,就像完成了一个提交在执行语句之前。这意味着DDL语句不能在另一个事务中执行,比如在事务控制语句中执行开始事务……提交,或与同一事务中的其他语句组合。

在MySQL 8.0中引入了MySQL数据字典,使得原子DDL成为可能。在早期的MySQL版本中,元数据存储在元数据文件、非事务性表和特定于存储引擎的字典中,这需要中间提交。MySQL数据字典提供的中心化、事务性的元数据存储消除了这一障碍,使得将DDL语句操作重组为原子操作成为可能。

本节将在以下主题中描述原子DDL特性:

支持DDL语句

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

  • 支持的表DDL语句包括创建,改变,下降用于数据库、表空间、表和索引的语句截断表声明。

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

    • 创建而且下降声明,如适用,改变用于存储程序、触发器、视图和可加载函数的语句。

    • 账户管理报表:创建,改变,下降,以及(如适用)重命名用户和角色的语句,以及格兰特而且撤销语句。

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

原子DDL特点

原子DDL语句的特征包括:

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

  • 在DDL操作期间,SQL层没有中间提交。

  • 适用:

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

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

    • 存储引擎支持DDL操作的重做和回滚Post-DDL阶段的DDL操作。

  • DDL操作的可见行为是原子的,它改变了一些DDL语句的行为。看到DDL语句行为的更改

DDL语句行为的更改

本节描述由于引入了原子DDL支持而导致的DDL语句行为变化。

  • 删除表如果所有命名表都使用支持ddl的原子存储引擎,那么操作就是完全原子的。该语句要么成功删除所有表,要么回滚。

    删除表如果指定表不存在,并且没有进行任何更改,则失败,并报错,无论存储引擎是什么。在下面的例子中演示了这种行为的变化,其中删除表语句失败,因为命名表不存在:

    创建表t1 (c1 INT)DROP TABLE t1, t2;错误1051 (42S02):未知表的测试。t2' mysql> SHOW TABLES;+----------------+ | Tables_in_test  | +----------------+ | t1  | +----------------+

    在引入原子DDL之前,删除表报告命名表不存在的错误,但成功地找到了存在的命名表:

    创建表t1 (c1 INT)DROP TABLE t1, t2;错误1051 (42S02):未知表的测试。t2' mysql> SHOW TABLES;空集合(0.00秒)
    请注意

    由于这种行为的改变,一个部分完成删除表MySQL 5.7复制源服务器上的语句在MySQL 8.0复制上复制失败。为了避免这种失败场景,请使用如果存在语法在删除表语句,以防止对不存在的表发生错误。

  • 删除数据库如果所有表都使用受ddl支持的原子存储引擎,那么它就是原子的。该语句要么成功删除所有对象,要么回滚。但是,最后才从文件系统中删除数据库目录,这不是原子操作的一部分。如果由于文件系统错误或服务器暂停而无法删除数据库目录,则删除数据库事务未回滚。

  • 对于不使用原子ddl支持的存储引擎的表,表删除发生在原子之外删除表删除数据库事务。这样的表删除是单独写入二进制日志的,这限制了存储引擎、数据字典和二进制日志之间的差异,在中断的情况下,最多只在一个表中删除表删除数据库操作。对于删除多个表的操作,不使用原子ddl支持的存储引擎的表会在使用该引擎的表之前删除。

  • 创建表,ALTER TABLE,重命名表,截断表,创建表空间,删除表空间对于使用原子ddl支持的存储引擎的表,操作要么完全提交,要么在操作期间服务器停止时回滚。在早期的MySQL版本中,这些操作的中断可能会导致存储引擎、数据字典和二进制日志之间的差异,或者留下孤立文件。重命名表只有当所有命名表都使用支持ddl的原子存储引擎时,操作才是原子的。

  • 从MySQL 8.0.21开始,在支持原子DDL的存储引擎上创建表……选择语句在使用基于行的复制时作为一个事务记录在二进制日志中。以前,它被记录为两个事务,一个用于创建表,另一个用于插入数据。两个事务之间的服务器故障或插入数据时的服务器故障可能导致复制空表。随着原子DDL支持的引入,创建表……选择语句现在对于基于行的复制是安全的,并且允许与基于gtid的复制一起使用。

    在同时支持原子DDL和外键约束的存储引擎上,不允许创建外键创建表……选择使用基于行的复制时的语句。外键约束可以稍后使用添加ALTER TABLE

    创建表……选择作为原子操作应用时,在插入数据时将在表上持有元数据锁,这将防止在操作期间对表进行并发访问。

  • 删除视图如果命名视图不存在,并且没有进行更改,则失败。在这个例子中演示了行为的变化,其中删除视图语句失败,因为命名视图不存在:

    mysql>创建测试视图。从t中选择*;mysql> DROP VIEW testviewA test.viewB;错误1051 (42S02):未知表的测试。查看mysql的>表+----------------+------------+ | Tables_in_test | Table_type  | +----------------+------------+ | viewA |视图  | +----------------+------------+

    在引入原子DDL之前,删除视图返回命名视图不存在的错误,但如果命名视图存在,则返回成功:

    mysql>创建测试视图。从t中选择*;mysql> DROP VIEW testviewA test.viewB;错误1051 (42S02):未知表的测试。查看mysql的>表空集合(0.00秒)
    请注意

    由于这种行为的改变,一个部分完成删除视图MySQL 5.7复制源服务器上的操作在MySQL 8.0复制副本上失败。为了避免这种失败场景,请使用如果存在语法在删除视图语句,以防止不存在的视图发生错误。

  • 不再允许部分执行帐户管理报表。帐户管理语句要么对所有命名用户成功,要么在发生错误时回滚,不起作用。在早期的MySQL版本中,命名多个用户的帐户管理语句可能对某些用户成功,而对其他用户失败。

    行为的变化在这个例子中得到了展示,其中第二个创建用户语句返回一个错误,但失败了,因为它不能对所有命名用户成功。

    创建用户userA创建用户userA, userB错误1396 (HY000): mysql>创建用户失败。user WHERE user LIKE 'user%';+-------+ | User | +-------+ | userA | +-------+

    在引入原子DDL之前,第二种创建用户语句对不存在的指定用户返回错误,但对存在的指定用户返回成功:

    创建用户userA创建用户userA, userB错误1396 (HY000): mysql>创建用户失败。user WHERE user LIKE 'user%';+-------+ | 用户  | +-------+ | userA | | userB  | +-------+
    请注意

    由于这种行为的改变,在MySQL 5.7复制源服务器上部分完成的帐户管理语句在MySQL 8.0复制上复制时失败。为了避免这种失败场景,请使用如果存在如果不存在在帐户管理语句中适当使用语法,以防止与命名用户相关的错误。

存储引擎的支持

目前,只有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可能执行准备而且执行阶段之前多次提交阶段。

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

  2. 执行:执行DDL操作。例如,执行创建例程创建表操作。

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

  4. Post-DDL:重播和删除DDL日志mysql.innodb_ddl_log表格为了确保可以安全地执行回滚,而不会导致不一致,重命名或删除数据文件等文件操作将在最后阶段执行。此阶段还将从mysql.innodb_dynamic_metadata的数据字典表删除表,截断表,以及重建表的其他DDL操作。

DDL日志被重播并从mysql.innodb_ddl_log表中Post-DDL阶段,无论DDL操作是提交还是回滚。DDL日志应该只保留在mysql.innodb_ddl_log如果服务器在DDL操作期间停止,则会显示表。在这种情况下,DDL日志被重播并在恢复后被删除。

在恢复情况下,DDL操作可能会在服务器重启时提交或回滚。过程中执行的数据字典事务提交如果在重做日志和二进制日志中出现DDL操作的阶段,则认为该操作是成功的,并进行前滚。否则,回滚不完整的数据字典事务InnoDB重放数据字典重做日志,并回滚DDL操作。

DDL日志查看

要查看写入的DDL日志mysql.innodb_ddl_log在涉及到的原子DDL操作期间InnoDB存储引擎,使innodb_print_ddl_logs让MySQL将DDL日志写入stderr.根据主机操作系统和MySQL配置,stderr可能是错误日志、终端或控制台窗口。看到第5.4.2.2节,“默认错误日志目的配置”

InnoDB将DDL日志写入mysql.innodb_ddl_log表支持DDL操作的重做和回滚。的mysql.innodb_ddl_log表是一个隐藏数据字典表,它驻留在mysql.ibd数据字典表空间。与其他隐藏数据字典表一样mysql.innodb_ddl_log在非调试版本的MySQL中不能直接访问表。(见第14.1节,“数据字典模式”)。它的结构mysql.innodb_ddl_log表对应于这个定义:

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 UTF8_BIN, new_file_path VARCHAR(512) COLLATE UTF8_BIN, KEY(thread_id));
  • id: DDL日志记录的唯一标识符。

  • thread_id:为每条DDL日志记录分配一个thread_id,它用于重播和删除属于特定DDL操作的DDL日志。当DDL操作涉及多个数据文件操作时,会产生多条DDL日志记录。

  • 类型: DDL操作类型。类型包括免费的(删除索引树),删除(删除一个文件),重命名(重命名文件)或下降删除元数据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日志strderr对于一个创建表操作。

mysql> SET GLOBAL innodb_print_ddl_logs=1CREATE TABLE t1 (c1 INT) ENGINE = InnoDB;
[注][000000]InnoDB: DDL log insert: [DDL record: DELETE SPACE, id=18, thread_id=7, space_id=5, old_file_path=./test/t1.]ibd][注][000000]InnoDB: DDL日志删除:通过id 18[注][000000]InnoDB: DDL日志插入:[DDL记录:删除缓存id = 19日thread_id = 7, table_id = 1058, new_file_path =测试/ t1][注][000000]InnoDB: DDL日志删除:通过id 19[注][000000]InnoDB: DDL日志插入:[DDL记录:自由、id = 20, thread_id = 7, space_id = 5, index_id = 132, page_no = 4)[注][000000]InnoDB: DDL日志删除:通过id 20[注][000000]InnoDB: DDL日志发布DDL:开始线程id: 7[注][000000]InnoDB:线程id: 7的DDL log post DDL: end