详解MySQL8.0原子DDL语法

01 原子DDL介绍

原子DDL语句将数据字典更新、存储引擎操作和与DDL操作相关联的二进制日志写入合并到单个原子操作中。该操作要么提交,对数据字典、存储引擎和二进制日志保留适用的更改,要么回滚。

在MySQL8.0中,原子DDL操作这一特性,支持表相关操作,例如create table、drop table等,也支持非表相关操作,例如create routine、drop trigger等。

其中:

支持的表操作包含:

drop、create、alter(操作对象是databases, tablespaces, tables, and indexes)语法、truncate语法

支持的非表操作包含:

create、drop、alter(操作对象是trigger、event、views、)

帐户管理语句:用户和角色的create、alter、drop和rename语句,以及grant和revoke语句

需要注意的是:跟表相关的DDL操作,需要保证存储引擎是Innodb的,非表相关的操作,则没有要求。

有些SQL语句不支持原子DDL,例如:

1、非Innodb存储引擎的表操作

2、install plugin和uninstall plugin操作(安装插件)

3、 install component和uninstallcomponent语句

4、create server、alter server和drop server语句(该语句是FEDERATED存储引擎使用的,可暂时忽略)

02 部分DDL操作的执行行为变化

原子操作的执行行为变化,跟数据字典的组织结构变化有关,在MySQL8.0 之前,Data Dictionary除了存在与.FRM, .TRG, .OPT 文件外,还存在于系统表中(MyISAM 非事务引擎表中),在MySQL8.0 ,Data Dictionary 全部存在于Data Dictionary Storage Engine(即 InnoDB表中),这使crash recovery 维持原子性成为了可能。下面的图描述了数据字典的结构变化。

在MySQL8.0之前,数据字典结构如下:

MySQL8.0之后,数据字典变为:

下面来看2个具体的语法变化:

(1) Drop语法的变化:

我们给数据库里面同时创建test1的表,并没有test2的表,然后执行drop table test1,test2;观察结果。

MySQL5.7表现:

mysql> create table test1(id int);
Query OK, 0 rows affected (0.01 sec)

mysql> show tables;
+----------------+
| Tables_in_yeyz |
+----------------+
| t1    |
| t2    |
| t3    |
| test1   |
+----------------+
4 rows in set (0.00 sec)

mysql> drop table test1,test2;
ERROR 1051 (42S02): Unknown table 'yeyz.test2'
mysql> show tables;
+----------------+
| Tables_in_yeyz |
+----------------+
| t1    |
| t2    |
| t3    |
+----------------+
3 rows in set (0.00 sec)

MySQL8.0的表现:

mysql> create table test1(id int);
Query OK, 0 rows affected (0.17 sec)

mysql> show tables;
+----------------+
| Tables_in_yeyz |
+----------------+
| test1   |
+----------------+
1 row in set (0.00 sec)

mysql> drop table test1,test2;
ERROR 1051 (42S02): Unknown table 'yeyz.test2'
mysql> show tables;
+----------------+
| Tables_in_yeyz |
+----------------+
| test1   |
+----------------+
1 row in set (0.00 sec)

可以看到,MySQL8.0中,当没有test2的时候,并没有删除test1这个表,它将整个语句完全回滚;而MySQL5.7中,误删除了test1这个表,没有将整个语句完全回滚。

基于这种处理机制的不同,因此,我们在使用MySQL5.7版本和MySQL8.0版本做主从复制的时候,如果使用了类似上面的语句,就会发生报错。因为二者的执行行为已经不一样了。要想解决这个问题,需要使用drop table if not exists语法,同样的,针对drop database、drop trigger等一系列操作,处理方法类似。还有一点值得注意,如果一个数据库中的所有表都是innodb的,那么drop database才是原子的,否则,drop database不是原子的。

(2) Create Table...Select 语法:

从MySQL 8.0.21开始,在支持原子DDL的存储引擎上,当使用基于row的复制模式时,CREATE TABLE...SELECT...,该语句作为一个事务记录在二进制日志中。之前的版本中,它被记录为两个事务,一个用于create表,另一个用于insert数据。两个事务之间或插入数据时发生服务器故障可能导致复制了一张空表。通过引入原子DDL支持,CREATE TABLE ...SELECT语句现在对于基于行的复制是安全的,并且允许与基于GTID的复制一起使用。

03 DDL 操作的log如何查看?

为了支持DDL操作的redo和rollback,InnoDB将DDL日志写入mysql.innodb_ddl_log表中,这个表存在于数据字典表空间中,如果用户想要看这个表里面的内容,需要打开参数:

mysql> show variables like '%innodb_print_ddl_logs%';
+-----------------------+-------+
| Variable_name   | Value |
+-----------------------+-------+
| innodb_print_ddl_logs | OFF |
+-----------------------+-------+
1 row in set (0.01 sec)

然后就可以在error log日志中看到ddl操作的日志了。相关日志如下:

[Note] [000000] InnoDB: DDL log insert : [DDL record: DELETE SPACE, id=18, thread_id=7,
space_id=5, old_file_path=./test/t1.ibd]
[Note] [000000] InnoDB: DDL log delete : by id 18
[Note] [000000] InnoDB: DDL log insert : [DDL record: REMOVE CACHE, id=19, thread_id=7,
table_id=1058, new_file_path=test/t1]
[Note] [000000] InnoDB: DDL log delete : by id 19
[Note] [000000] InnoDB: DDL log insert : [DDL record: FREE, id=20, thread_id=7,
space_id=5, index_id=132, page_no=4]
[Note] [000000] InnoDB: DDL log delete : by id 20
[Note] [000000] InnoDB: DDL log post ddl : begin for thread id : 7
[Note] [000000] InnoDB: DDL log post ddl : end for thread id : 7

mysql.innodb_ddl_log这个表的刷盘时机不受innodb_flush_logs_at_trx_commit参数的影响,这么做的目的是为了避免数据文件被DDL操作修改了,但是对应的redo log还没有刷新到磁盘,导致恢复或者回滚的时候报错。

最后,我们介绍下整个原子DDL操作的几个阶段:

1、准备阶段:创建需要的对象,写入DDL log到mysql.innodb_ddl_log表,DDl log定义了如何前滚和回滚DDL操作

2、执行阶段:执行DDL的操作流程

3、提交阶段:更新数据字典,并提交数据字典事务

4、Post-DDL阶段:从mysql.innodb_ddl_log表重放并删除DDL日志。为了确保可以安全地执行回滚而不会引起不一致,在此最后阶段执行磁盘上的文件操作,例如重命名或删除数据文件。此阶段还将从mysql.innodb_dynamic_metadata数据字典表中删除动态元数据,以用于DROP TABLE,TRUNCATE TABLE和其他重建表的DDL操作。

以上就是详解MySQL8.0原子DDL语法的详细内容,更多关于MySQL8.0原子DDL语法的资料请关注我们其它相关文章!

(0)

相关推荐

  • MySQL8.0 DDL原子性特性及实现原理

    1. DDL原子性概述 8.0之前并没有统一的数据字典dd,server层和引擎层各有一套元数据,sever层的元数据包括(.frm,.opt,.par,.trg等),用于存储表定义,分区表定义,触发器定义等信息:innodb层也有自己一套元数据,包括表信息,索引信息等,这两套元数据并没有机制保证一致性,这就导致了在异常情况下可能存在元数据不一致问题,一种典型场景下,删表操作,sever层的frm已经成功删除了,但引擎层数据字典并没有更新,导致再建重名表失败的问题.同样的,比如drop tabl

  • 解析MySQL8.0新特性——事务性数据字典与原子DDL

    前言 事务性数据字典与原子DDL,是MySQL 8.0推出的两个非常重要的新特性,之所以将这两个新特性放在一起,是因为两者密切相关,事务性数据字典是前提,原子DDL是一个重要应用场景. MySQL 8.0之前的数据字典 MySQL 8.0之前的数据字典,主要由以下三部分组成: (1)操作系统文件 db.opt:数据库元数据信息 frm:表元数据信息 par:表分区元数据信息 TRN/TRG:触发器元数据信息 ddl_log.log:DDL过程中产生的元数据信息 (2)mysql库下的非InnoD

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

    MySQL 8.0开始支持原子数据定义语言(DDL)语句.此功能称为原子DDL.原子DDL语句将与DDL操作关联的数据字典更新,存储引擎操作和二进制日志写入组合到单个原子事务中.即使服务器在操作期间暂停,也会提交事务,并将适用的更改保留到数据字典,存储引擎和二进制日志,或者回滚事务. 通过在MySQL 8.0中引入MySQL数据字典,可以实现Atomic DDL.在早期的MySQL版本中,元数据存储在元数据文件,非事务性表和存储引擎特定的字典中,这需要中间提交.MySQL数据字典提供的集中式事务

  • 详解MySQL8.0原子DDL语法

    01 原子DDL介绍 原子DDL语句将数据字典更新.存储引擎操作和与DDL操作相关联的二进制日志写入合并到单个原子操作中.该操作要么提交,对数据字典.存储引擎和二进制日志保留适用的更改,要么回滚. 在MySQL8.0中,原子DDL操作这一特性,支持表相关操作,例如create table.drop table等,也支持非表相关操作,例如create routine.drop trigger等. 其中: 支持的表操作包含: drop.create.alter(操作对象是databases, tab

  • 详解MySQL8.0 密码过期策略

    MySQL8.0.16开始,可以设置密码的过期策略,今天针对这个小的知识点进行展开. 1.手工设置单个密码过期 MySQL8.0中,我们可以使用alter user这个命令来让密码过期. 首先我们创建账号yeyz,密码是yeyz [root@VM-0-14-centos ~]# /usr/local/mysql-8.0.19-el7-x86_64/bin/mysql -uyeyz -pyeyz -h127.0.0.1 -P4306 -e "select 1" mysql: [Warni

  • 详解MySQL8.0​ 字典表增强

    MySQL中数据字典是数据库重要的组成部分之一,INFORMATION_SCHEMA首次引入于MySQL 5.0,作为一种从正在运行的MySQL服务器检索元数据的标准兼容方式.用于存储数据元数据.统计信息.以及有关MySQL server的访问信息(例如:数据库名或表名,字段的数据类型和访问权限等). 8.0之前: 1.元数据来自文件 2.采用MEMORY表引擎 3.frm文件 存放表结构信息 4.opt文件,记录了每个库的一些基本信息,包括库的字符集等信息 5..TRN,.TRG文件用于存放触

  • 详解MySQL8.0+常用命令

    开启远程访问 通过以下命令开启root用户远程访问权限: CREATE USER 'root'@'%' IDENTIFIED BY 'password'; GRANT ALL ON *.* TO 'root'@'%'; ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'password'; FLUSH PRIVILEGES; 注:其中,password为root的密码,FLUSH PRIVILEGES为刷新权限 导入数

  • 详解mysql8.0创建用户授予权限报错解决方法

    问题一: 会报错的写法: GRANT ALL PRIVILEGES ON *.*  'root'@'%' identified by '123123' WITH GRANT OPTION; 以下是正确的写法: grant all privileges on *.* to 'root'@'%' ; 可见,在授权的语句中需要去掉 IDENTIFIED BY 'password'; 单独授予某种权限的写法: GRANT SELECT ON oilsystem.input TO 'u5'@'localh

  • 详解mysql8.018在linux上安装与配置过程

    windows下安装介绍:去看看–>mysql8.018在windows下安装介绍 Linux平台: 以下操作以mysql 8.0.18,系统为Ubuntu 16.04.6 LTS (GNU/Linux 4.4.0-142-generic x86_64)为例: A. 自动安装 sudo apt-get install mysql-server sudo apt-get install mysql-client sudo apt-get install libmysqlclient-dev B.

  • 详解C++11原子类型与原子操作

    1.认识原子操作 原子操作就是在多线程程序中"最小的且不可并行化的"操作,意味着多个线程访问同一个资源时,有且仅有一个线程能对资源进行操作.通常情况下原子操作可以通过互斥的访问方式来保证,例如Linux下的互斥锁(mutex),Windows下的临界区(Critical Section)等.下面看一个Linux环境使用POSIX标准的pthread库实现多线程下的原子操作: #include <pthread.h> #include <iostream> usi

  • 详解MySQL8的新特性ROLE

    [MySQL的ROLE解决了什么问题] 假设你是一个职业素养良好的DBA比较同时又比较注重权限管理的话:可能遇到过这样的问题,数据库中有多个开发人员的账号:有一天要建 一个新的schema,如果你希望之前所有的账号都能操作这个schema下的表的话,在mysql-8.0之前你要对第一个账号都单独的赋一次权. mysql-8.0.x所权限抽象了出来用ROLE来表示,当你为ROLE增加新的权限的时候,与这个ROLE关联的所有用户的权限也就一并变化了:针对 上面提到的场景在mysql-8.0.x下只要

  • 详解Vue3.0 + TypeScript + Vite初体验

    项目创建 npm: $ npm init vite-app <project-name> $ cd <project-name> $ npm install $ npm run dev or yarn: $ yarn create vite-app <project-name> $ cd <project-name> $ yarn $ yarn dev 项目结构 main.js 在个人想法上,我觉得createApp()是vue应用的实例,createApp

  • 详解vite2.0配置学习(typescript版本)

    介绍 尤于溪的原话. vite与 Vue CLI 类似,vite 也是一个提供基本项目脚手架和开发服务器的构建工具. vite基于浏览器原生ES imports的开发服务器.跳过打包这个概念,服务端按需编译返回. vite速度比webpack快10+倍,支持热跟新, 但是出于处于测试阶段. 配置文件也支持热跟新!!! 创建 执行npm init @vitejs/app ,我这里选择的是vue-ts 版本 "vite": "^2.0.0-beta.48" alias别

随机推荐