一、什么是DDL?#
DDL全称:Data Definition Language
它包含三个主要的关键字:create、drop、alter
操作 | statement |
创建数据库 | create database |
删除数据库 | drop database |
修改数据库 | alter database |
创建表 | create table |
删除表 | drop table |
修改表 | alter table |
创建索引 | create index |
删除索引 | drop index |
二、表级锁和元数据锁#
MySQL的表级锁有两种,一种是表锁,一种是元数据锁MDL
2.1、什么是表锁?#
表锁的语法: lock tables ... read/write
释放时机:通过unlock tables 主动释放,当客户端断开时也会自动释放。
例如:线程A执行: lock tables t1 read, t2 write; 那其他线程写t1和读写t2时都会被阻塞, 而且线程A在unlock tables 之前,也只能执行读t1,读写t2,它自己也不被允许写t1。
2.2、什么是MDL?#
元数据锁也是一种表级锁:metadata lock。
作用:
我们不需要显示的使用它,当访问一个表的时候,它会被自动加上。MDL锁的作用就是保证读写的正确性
说白了,就是实现:当有用户对表执行DML相关操作时,其他线程不能把表结构给改了(想改表结构也可以,等排在它前面的DML全部执行完)。反之,当有线程在更改表结构时,其他线程需要执行的DML也会被阻塞住。
特性:
1、系统默认添加。
2、读锁之间不互斥。
3、读写锁之间互斥。
三、什么是无损DDL?#
需求:
一般对公司对业务线来说,总是难免遇到需要修改线上表结构的需求。比如搞个活动,结果发现:现有的表中的列不够用了,那么就需要对现有的表进行无损DDL操作,添加一列。
有损DDL
为什么直接执行alter table add column
有损?
如下图所示:你alter table时是需要获取元数据锁的写锁的,而所有的DML操作又会被默认的加上元数据读锁。如果所有的语句都是DML语句那皆大欢喜,大家都是读锁彼此不影响。
但是你看上图这突然整出来一个alter语句,一旦等他持有写锁后,去执行DDL语句时期间,所有的DML语句全部被阻塞,我们称这种情况对业务来说是有损的。
无损DDL
所谓的无损是相对于业务来说的,如果能做到执行DDL的过程中,对业务无影响,那我们称这种ddl是无损的。
至于如何无损的解决这个问题,接着看下文。
四、DDL重建表#
什么是重建表?为什么要重建表?
当我执行delete语句删除表A中的数据时,对应Innodb来说其实只是在标记删除,而是不实实在在的将表空间中的数据删除,对应innodb来将被标记删除的位置是可以可重复使用。
那么delete语句多了,表空间上的空洞就多了,磁盘的占用量也只增不减。这时我们就得重建表。缩小表A上的空洞。
重建表的方法:
方式1、可以新建一个新的表,然后将原表中的数据按照id生序一次拷贝过去。
方式2、也可以执行alter table A engine=InnoDB
来重建表。
这里的alter table 其实就是DDL语句
Mysql5.5之前重建表#
在5.5之前,mysql执行alter table A engine=InnoDB
的流程如下图:
在上面的过程中,MySQL会自动的为我们创建临时表,拷贝数据,交换表名,以及删除旧表。
特点:
一、这个过程并不是安全的。因为在往tmp表中写数据的过程中,如果有业务流量写入表A,而且写入的位置是不久前完成往tmp中拷贝的位置,就会导致数据的丢失。
二、即使是MySQL会我们自动的创建临时表,数据拷贝的过程依然是在MySQL-Server层面做的。
Mysql5.6之后重建表#
重建表的过程如下图:
1、创建一个tmp_file, 扫描表A主键的所有数据页。
2、使用数据页中的记录生成B+树,存储进tmp_file中。
这一步是对针对数据文件的操作。由innodb直接完成。
3、在生成转存B+数的过程中,将针对A的写操作记录在row_log日志中。
4、完成了B+树的转存后,将row_log中记录的日志在tmp_file中回放。
5、使用临时文件替换A中的数据文件。
可以看到,这个过程其实已经实现无损了。因为在做数据迁移的过程中,允许对原表进行CRUD
局限性:
这种DDL本质上是在替换表空间中的数据文件,仅仅是用于对原表进行无损DDL瘦身。而不是解决我们开题所说的动态无损加列的情况。