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操作的重做和回滚Post-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秒)
删除数据库
如果所有表都使用受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版本中,命名多个用户的帐户管理语句可能对某些用户成功,而对其他用户失败。
行为的变化在这个例子中得到了展示,其中第二个
创建用户
语句返回一个错误,但失败了,因为它不能对所有命名用户成功。创建用户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
可能执行准备而且执行阶段之前多次提交阶段。
DDL日志被重播并从mysql.innodb_ddl_log
表中Post-DDL阶段,无论DDL操作是提交还是回滚。DDL日志应该只保留在mysql.innodb_ddl_log
如果服务器在DDL操作期间停止,则会显示表。在这种情况下,DDL日志被重播并在恢复后被删除。
在恢复情况下,DDL操作可能会在服务器重启时提交或回滚。过程中执行的数据字典事务提交如果在重做日志和二进制日志中出现DDL操作的阶段,则认为该操作是成功的,并进行前滚。否则,回滚不完整的数据字典事务InnoDB
重放数据字典重做日志,并回滚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