欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

MySQL8.0新特性之支持原子DDL语句

程序员文章站 2022-07-05 17:19:50
mysql 8.0开始支持原子数据定义语言(ddl)语句。此功能称为原子ddl。原子ddl语句将与ddl操作关联的数据字典更新,存储引擎操作和二进制日志写入组合到单个原子事...

mysql 8.0开始支持原子数据定义语言(ddl)语句。此功能称为原子ddl。原子ddl语句将与ddl操作关联的数据字典更新,存储引擎操作和二进制日志写入组合到单个原子事务中。即使服务器在操作期间暂停,也会提交事务,并将适用的更改保留到数据字典,存储引擎和二进制日志,或者回滚事务。

   通过在mysql 8.0中引入mysql数据字典,可以实现atomic ddl。在早期的mysql版本中,元数据存储在元数据文件,非事务性表和存储引擎特定的字典中,这需要中间提交。mysql数据字典提供的集中式事务元数据存储消除了这一障碍,使得将ddl语句操作重组为原子事务成为可能。

官方文档:

1、支持的ddl语句

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

①:受支持的表ddl语句包括 create,alter和 drop对数据库,表,表和索引,以及语句 truncate table声明。
②:支持的非表ddl语句包括:
   create和drop 语句,以及(如果适用)alter 存储程序,触发器,视图和用户定义函数(udf)的语句。
   账户管理语句: create,alter, drop,,如果适用, rename报表用户和角色,以及grant 和revoke报表。

1.1、原子ddl功能不支持以下语句:

①:涉及除存储引擎之外的存储引擎的与表相关的ddl语句innodb。
②:install plugin和 uninstall plugin 陈述。
③:install component和 uninstall component 陈述。
④:create server, alter server和 drop server语句。

2、原子ddl特性:

①:元数据更新,二进制日志写入和存储引擎操作(如果适用)将合并为单个事务。
②:在ddl操作期间,sql层没有中间提交。
③:在适用的情况下:
    数据字典,程序,事件和udf高速缓存的状态与ddl操作的状态一致,这意味着更新高速缓存以反映ddl操作是成功完成还是回滚。
    ddl操作中涉及的存储引擎方法不执行中间提交,并且存储引擎将自身注册为ddl事务的一部分。
    存储引擎支持ddl操作的重做和回滚,这在ddl操作的 post-ddl阶段执行。
④:ddl操作的可见行为是原子的,这会更改某些ddl语句的行为

注意:

  原子或其他ddl语句隐式结束当前会话中处于活动状态的任何事务,就好像您commit在执行语句之前完成了一样。这意味着ddl语句不能在另一个事务中,在事务控制语句中执行 start transaction ... commit,或者与同一事务中的其他语句结合使用。

3、ddl语句行为的变化

3.1、drop table:

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

drop table如果命名表不存在,并且未进行任何更改(无论存储引擎如何),则会失败并显示错误。如下所示:

mysql> create table t1 (c1 int);
mysql> drop table t1, t2;
error 1051 (42s02): unknown table 'test.t2'
mysql> show tables;
+----------------+
| tables_in_test |
+----------------+
| t1    |
+----------------+

在引入原子ddl之前, drop table虽然会报错误表不存在,但是存在的表会被执行成功,如下:

mysql> create table t1 (c1 int);
mysql> drop table t1, t2;
error 1051 (42s02): unknown table 'test.t2'
mysql> show tables;
empty set (0.00 sec)

注意:

   由于行为的这种变化,drop table会在 mysql 5.7主服务器上的部分完成 语句在mysql 8.0从服务器上复制时失败。要避免此故障情形,请在drop table语句中使用if exists语法以防止对不存在的表发生错误

3.2、drop database:

   如果所有表都使用原子ddl支持的存储引擎,则为atomic。该语句要么成功删除所有对象,要么回滚。但是,从文件系统中删除数据库目录是最后一次,并且不是原子事务的一部分。如果由于文件系统错误或服务器暂停而导致数据库目录的删除失败, drop database则不会回滚事务。

3.3、对于不使用原子ddl支持的存储引擎的表,表删除发生在原子 drop table或 drop database事务之外。这样的表删除被单独写入二进制日志,这在中断drop table或 drop database操作的情况下将存储引擎,数据字典和二进制日志之间的差异限制为最多一个表 。对于删除多个表的操作,不使用原子ddl支持的存储引擎的表将在执行之前删除。

3.4、create table, alter table, rename table, truncate table, create tablespace,和 drop tablespace对使用原子ddl支持的存储引擎表执行的操作要么完全提交或如果服务器的操作时停止回滚。在早期的mysql版本中,这些操作的中断可能会导致存储引擎,数据字典和二进制日志之间的差异,或留下孤立文件。rename table如果所有命名表都使用原子ddl支持的存储引擎,则操作只是原子操作。

3.5、drop view:

 如果命名视图不存在且未进行任何更改,则会失败。在此示例中演示了行为更改,其中 drop view语句失败,因为命名视图不存在,如下:

mysql> create view test.viewa as select * from t;
mysql> drop view test.viewa, test.viewb;
error 1051 (42s02): unknown table 'test.viewb'
mysql> show full tables in test where table_type like 'view';
+----------------+------------+
| tables_in_test | table_type |
+----------------+------------+
| viewa   | view  |
+----------------+------------+

在引入原子ddl之前, 使用drop view删除视图会报错,但是存在的视图会被成功删除:

mysql> create view test.viewa as select * from t;
mysql> drop view test.viewa, test.viewb;
error 1051 (42s02): unknown table 'test.viewb'
mysql> show full tables in test where table_type like 'view';
empty set (0.00 sec)

注意:

   由于行为的这种变化,drop view在mysql 5.7主服务器上的部分完成 操作在mysql 8.0从服务器上复制时会失败。要避免此故障情形,请在drop view语句中使用if exists语法以防止对不存在的视图发生错误。

3.6、不再允许部分执行帐户管理声明。帐户管理语句对所有命名用户成功或回滚,如果发生错误则无效。在早期的mysql版本中,为多个用户命名的帐户管理语句可能对某些用户成功,而对其他用户则失败。

如下:其中第二个create user 语句返回错误但失败,因为它无法对所有命名用户成功。

mysql> create user usera;
mysql> create user usera, userb;
error 1396 (hy000): operation create user failed for 'usera'@'%'
mysql> select user from mysql.user where user like 'user%';
+-------+
| user |
+-------+
| usera |
+-------+

在引入原子ddl之前,第二个 使用create user语句创建用户会返回一个错误,但是不存在的用户会成功创建,:

mysql> create user usera;
mysql> create user usera, userb;
error 1396 (hy000): operation create user failed for 'usera'@'%'
mysql> select user from mysql.user where user like 'user%';
+-------+
| user |
+-------+
| usera |
| userb |
+-------+

注意:

   由于行为的这种变化,mysql 5.7主服务器上部分会成功执行,会在mysql 8.0从服务器上复制时失败。要避免此故障情形,请在创建用户的命令中使用if exists或 if not exists语法,以防止与命名用户相关的错误。

4、存储引擎支持:目前只有innodb存储引擎支持原子ddl

   目前,只有innodb存储引擎支持原子ddl。不支持原子ddl的存储引擎免于ddl原子性。涉及豁免存储引擎的ddl操作仍然能够引入操作中断或仅部分完成时可能发生的不一致。
   要支持重做和回滚ddl操作, innodb请将ddl日志写入 mysql.innodb_ddl_log表,该表是驻留在mysql.ibd数据字典表空间中的隐藏数据字典表 。
要mysql.innodb_ddl_log在ddl操作期间查看写入表的ddl日志 ,请启用 innodb_print_ddl_logs 配置选项。

注意:

mysql.innodb_ddl_log无论innodb_flush_log_at_trx_commit 设置多少,对表的 更改的重做日志 都会立即刷新到磁盘 。立即刷新重做日志可以避免ddl操作修改数据文件的情况,但是mysql.innodb_ddl_log由这些操作产生的对表的更改的重做日志 不会持久保存到磁盘。这种情况可能会在回滚或恢复期间导致错误。

innodb存储引擎分阶段执行ddl操作。ddl操作 alter table可以在commit阶段之前多次执行 prepare和perform阶段:

准备:创建所需对象并将ddl日志写入 mysql.innodb_ddl_log表中。ddl日志定义了如何前滚和回滚ddl操作。
执行:执行ddl操作。例如,为create table操作执行创建例程。
提交:更新数据字典并提交数据字典事务。
post-ddl:重播并从mysql.innodb_ddl_log表中删除ddl日志。为了确保可以安全地执行回滚而不引入不一致性,在最后阶段执行文件操作,例如重命名或删除数据文件。这一阶段还从删除的动态元数据 mysql.innodb_dynamic_metadata的数据字典表drop table,truncate table和该重建表其他ddl操作。

注意:

  无论事务是提交还是回滚, ddl日志都会在post-ddl阶段重播并从表中删除 。mysql.innodb_ddl_log如果服务器在ddl操作期间暂停,则ddl日志应仅保留在表中。在这种情况下,ddl日志将在恢复后重播并删除。

  在恢复情况下,可以在重新启动服务器时提交或回滚ddl事务。如果在重做日志和二进制日志中存在在ddl操作的提交阶段期间执行的数据字典事务,则 该操作被视为成功并且前滚。否则,在innodb重放数据字典重做日志时回滚不完整的数据字典事务 ,并回滚ddl事务。

5、查看ddl日志:

   innodb将ddl日志写入 mysql.innodb_ddl_log表以支持重做和回滚ddl操作。该 mysql.innodb_ddl_log表是隐藏在mysql.ibd数据字典表空间中的隐藏数据字典表 。与其他隐藏数据字典表一样,mysql.innodb_ddl_log在非调试版本的mysql中无法直接访问该 表。