MySQL 8.0支持原子数据定义语言(DDL)语句。这个特性被称为原子DDL.原子DDL语句将与DDL操作相关联的数据字典更新、存储引擎操作和二进制日志写入组合为单个原子操作。该操作要么被提交,并将适用的更改持久化到数据字典、存储引擎和二进制日志,要么被回滚,即使在操作期间服务器停止。
原子DDL不是交易DDL..DDL语句,无论是原子的还是其他的,都会隐式地结束当前会话中活动的任何事务,就好像您已经完成了一个提交
在执行语句之前。这意味着DDL语句不能在另一个事务中执行,比如在事务控制语句中开始事务……提交
,或与同一事务中的其他报表组合。
在MySQL 8.0中引入MySQL数据字典使得原子DDL成为可能。在早期的MySQL版本中,元数据存储在元数据文件、非事务性表和特定于存储引擎的字典中,这就需要中间提交。由MySQL数据字典提供的集中式、事务性元数据存储消除了这个障碍,使得将DDL语句操作重组为原子操作成为可能。
原子DDL特性将在本节的以下主题中进行描述:
原子DDL特性同时支持表和非表DDL语句。表相关的DDL操作需要存储引擎支持,而非表的DDL操作不需要。目前,只有Innodb.
存储引擎支持原子DDL。
支持的表DDL语句包括
创造
,改变,更改
, 和下降
语句用于数据库、表空间、表和索引,以及截断表
声明。支持的非表DDL语句包括:
原子DDL特性不支持以下语句:
原子DDL语句的特征包括:
元数据更新、二进制日志写入和存储引擎操作(在适用的情况下)被组合成单个原子操作。
在DDL操作期间,SQL层没有中间提交。
适用:
数据字典、例程、事件和可加载函数缓存的状态与DDL操作的状态一致,这意味着缓存被更新,以反映DDL操作是否成功完成或回滚。
涉及DDL操作的存储引擎方法不执行中间提交,并且存储引擎作为DDL操作的一部分寄存自身。
存储引擎支持重做和回滚DDL操作,该操作是在此中执行的后DDL.阶段的DDL操作。
DDL操作的可见行为是原子性的,它会改变一些DDL语句的行为。看到DDL语句行为的变化.
本节描述由于引入原子DDL支持而导致的DDL语句行为的变化。
删除表
如果所有命名表都使用原子ddl支持的存储引擎,则操作是完全原子的。语句要么成功删除所有表,要么回滚。删除表
如果命名表不存在,且无论存储引擎如何,都没有进行任何更改,则会失败并报错。行为中的这种变化在下面的示例中演示,其中删除表
语句失败,因为命名表不存在:mysql> CREATE TABLE t1 (c1 INT);mysql> DROP TABLE t1, t2;错误1051(42s02):未知表'test.t2'mysql> show table;+----------------+ | Tables_in_test | +----------------+ | t1 | +----------------+
在引入原子DDL之前,
删除表
对于不存在的命名表报告错误,但是对于存在的命名表报告成功:mysql> CREATE TABLE t1 (c1 INT);mysql> DROP TABLE t1, t2;错误1051(42s02):未知表'test.t2'mysql> show table;空集(0.00秒)
删除数据库
是原子的,如果所有表都使用原子的ddl支持的存储引擎。该语句要么成功删除所有对象,要么被回滚。但是,最后从文件系统删除数据库目录,这不是原子操作的一部分。如果由于文件系统错误或服务器停止导致删除数据库目录失败,则删除数据库
事务没有回滚。对于不使用原子ddl支持的存储引擎的表,表删除发生在原子引擎之外
删除表
或者删除数据库
事务。这样的表删除被单独写入二进制日志,这样在中断的情况下,存储引擎、数据字典和二进制日志之间的差异最多限制在一个表删除表
或者删除数据库
操作。对于删除多个表的操作,不使用原子ddl支持的存储引擎的表将在使用原子ddl支持的存储引擎的表之前删除。创建表
,ALTER TABLE
,重命名表
,截断表
,创建表空间
, 和删除表空间
对于使用原子ddl支持的存储引擎的表的操作,如果服务器在操作期间停止,则会完全提交或回滚。在早期的MySQL版本中,这些操作的中断可能会导致存储引擎、数据字典和二进制日志之间的差异,或者留下孤儿文件。重命名表
如果所有命名表都使用一个受ddl支持的原子存储引擎,则操作只是原子的。从MySQL 8.0.21开始,在支持原子DDL的存储引擎上
创建表……选择
当使用基于行的复制时,语句被记录为二进制日志中的一个事务。以前,它被记录为两个事务,一个用于创建表,另一个用于插入数据。两个事务之间或插入数据时的服务器故障可能导致复制空表。通过引入原子DDL支持,创建表……选择
现在对基于行的复制安全,并允许使用基于GTID的复制。在支持原子DDL和外键限制的存储引擎上,不允许创建外键
创建表……选择
在使用基于行的复制时。外键约束可以在以后使用ALTER TABLE
.当
创建表……选择
作为原子操作应用时,在插入数据时将在表上持有元数据锁,这将在操作期间阻止对表的并发访问。删除视图
如果指定视图不存在,且没有进行任何更改,则失败。在这个例子中演示了行为的改变,其中删除视图
语句失败,因为不存在命名视图:mysql>创建视图test.viewa为select * from t;MySQL> Drop View Test.Viewa,test.ViewB;错误1051(42s02):未知表'test.viewb'mysql>在测试中显示完整表,其中table_type等'查看';+----------------+------------+ | Tables_in_test | Table_type | +----------------+------------+ | viewA |视图 | +----------------+------------+
在引入原子DDL之前,
删除视图
对于不存在的命名视图返回错误,但对于存在的命名视图返回成功:mysql>创建视图test.viewa为select * from t;MySQL> Drop View Test.Viewa,test.ViewB;错误1051(42s02):未知表'test.viewb'mysql>在测试中显示完整表,其中table_type等'查看';空集(0.00秒)
不再允许部分执行帐户管理报表。帐户管理语句对所有命名用户都成功,或者在发生错误时回滚,并且没有影响。在早期的MySQL版本中,命名多个用户的帐户管理语句可能对某些用户成功,对其他用户失败。
在这个例子中演示了行为的改变,在第二个例子中
创建用户
语句返回错误但失败,因为它不能成功对所有命名用户。mysql> CREATE USER userera;mysql> CREATE USER userA, userB;ERROR 1396 (HY000): Operation CREATE USER failed for 'userA'@'%' mysql> SELECT USER FROM mysqluser WHERE user LIKE 'user%';+-------+ |用户| +-------+ | userA | +-------+
在引入原子DDL之前,第二个
创建用户
如果指定用户不存在,则返回错误,但如果指定用户存在,则返回成功:mysql> CREATE USER userera;mysql> CREATE USER userA, userB;ERROR 1396 (HY000): Operation CREATE USER failed for 'userA'@'%' mysql> SELECT USER FROM mysqluser WHERE user LIKE 'user%';+-------+ | 用户 | +-------+ | userA | | userB | +-------+
请注意由于这种行为的改变,当在MySQL 8.0副本上复制时,在MySQL 5.7复制源服务器上部分完成的帐户管理语句失败。要避免这种失败场景,请使用
如果存在
或者如果不存在
语法,酌情在帐户管理语句中,以防止与命名用户相关的错误。
目前,只有Innodb.
存储引擎支持原子DDL。不支持原子DDL的存储引擎不受DDL原子性的限制。涉及豁免存储引擎的DDL操作仍然能够引入不一致,当操作中断或仅部分完成时,可能会出现不一致。
支持重做和回滚DDL操作,Innodb.
将DDL日志写入mysql.innodb_ddl_log
对象中的隐藏数据字典表mysql.ibd
数据字典表空间。
查看写入到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
可以执行准备和履行阶段之前多次犯罪阶段。
DDL日志将被重放并从mysql.innodb_ddl_log
表中的表后DDL.相位,无论DDL操作是如何承诺还是回滚。DDL日志应该只留在mysql.innodb_ddl_log
表,如果服务器在DDL操作期间暂停。在这种情况下,DDL日志将在恢复后重新播放并删除。
在恢复情况下,可能会在服务器重新启动时提交或回滚DDL操作。操作期间执行的数据字典事务犯罪如果DDL操作的一个阶段出现在重做日志和二进制日志中,则认为该操作成功并被前滚。否则,不完整的数据字典事务将在何时回滚Innodb.
重放数据字典重做日志,并回滚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
表对应于这个定义:
create table mysql.innodb_ddl_log(id bigint unsigned not null auto_increment unligned 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 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 = 1;MySQL>创建表T1(C1 INT)引擎= InnoDB;
[注释][000000]InnoDB: DDL log insert: [DDL record: DELETE SPACE, id=18, thread_id=7, space_id=5, old_file_path=./test/t1. log]日志插入[注释][000000]InnoDB: DDL log insert: [DDL record: REMOVE CACHE, id=19, thread_id=7, table_id=1058, new_file_path=test/t1][注释][000000]InnoDB: DDL log insert: [DDL record: REMOVE CACHE, id=19, thread_id=7, table_id=1058, new_file_path=test/t1][注释][000000]FREE, id=20, thread_id=7, space_id=5, index_id=132, page_no=4][注释][000000]InnoDB: DDL log delete: by id 20[注释][000000]InnoDB: DDL log post DDL: begin for thread id: 7[注释][000000]InnoDB: DDL log post DDL: end for thread id: 7