在 DDL 语句中的变化

Exisi 2023-01-25 16:32:12
Categories: Tags:
  • 如果所有命名表都使用原子 DDL 支持的存储引擎,则操作是完全原子的。该语句要么成功删除所有表,要么回滚。

 

  • 对于使用支持原子DDL的存储引擎的表,CREATE TABLEALTER TABLERENAME TABLETRUNCATE TABLECREATE TABLE SPACEDROP TABLE操作要么完全提交,要么在服务器运行期间停止时回滚。在早期的MySQL版本中,这些操作的中断可能会导致存储引擎、数据字典和二进制日志之间的差异,或者留下孤立文件。

 

 

 

DROP TABLE

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

 

  • 如果命名表不存在,并且无论存储引擎如何,都不会进行任何更改,则 DROP TABLE 将失败并显示错误。

 

  • 对于删除多个表的操作,不使用原子DDL支持的存储引擎的表会在使用原子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;

+------------------+

| Tables_in_test |

+------------------+

| t1                     |

+------------------+

  • 由于原子DDL的这种变化,在MySQL 8.0副本上复制MySQL 5.7复制源服务器上部分完成的DROP TABLE语句时会失败。若要避免此失败情况,请在 DROP TABLE 语句中使用语法,以防止不存在的表发生错误,请使用IF EXISTS

 

  • 从文件系统中删除数据库目录是最后发生的,并且不是原子操作的一部分。如果由于文件系统错误或服务器停止而导致删除数据库目录失败,则不会回滚 DROP DATABASE 事务。

 

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

 

 

 

CREATE TABLE ... SELECT

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

 

  • 在同时支持原子 DDL 和外键约束的存储引擎上,当使用基于行的复制时,不允许在 CREATE TABLE ... SELECT 语句中创建外键。但是可以在其后使用 ALTER TABLE 添加外键约束。

 

  • CREATE TABLE ... SELECT 作为原子操作应用时,在插入数据时会在表上持有元数据锁,从而防止在操作期间并发访问表。

 

 

 

DROP VIEW

  • 如果命名视图不存在并且不进行任何更改,则 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)

  • 由于这种行为变化,在 MySQL 5.7 复制源服务器上部分完成的 DROP VIEW 操作在 MySQL 8.0 副本上复制时会失败。要避免这种失败情况,请在 DROP VIEW 语句中使用 IF EXISTS 语法来防止不存在的视图发生错误。

 

 

 

CREATE USER

  • 不再允许部分执行账户管理报表。帐户管理语句要么对所有指定用户成功,要么回滚并且在发生错误时无效。在早期的 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 8.0 副本上复制时,MySQL 5.7 复制源服务器上部分完成的帐户管理语句会失败。为避免这种失败情况,请在帐户管理语句中酌情使用 IF EXISTS IF NOT EXISTS 语法,以防止与命名用户相关的错误。

 

 

来自 <https://dev.mysql.com/doc/refman/8.0/en/atomic-ddl.html>