关于DDL的ONLINE和OFFLINE,通俗的讲:
-
ONLINE:在执行DDL时允许DML操作
-
OFFLINE:在执行DDL时不允许DML操作
在生产上的场景就是业务正在运行,DBA需要在表中添加新的字段同时不能影响该表的写操作就是ONLINE DDL。也就是说,所谓的ONLINE和OFFLINE更准确是针对 ALTER TABLE 语句。
在 MySQL 5.6 版本之后,引入了 ALGORITHM 参数来控制并发时 ALTER TABLE 语句的算法,官方不建议指定该参数的值,MySQL 自己会选择最优的算法。语法如下:
ALTER TABLE TABLE_NAME ADD COLUMN COLUMN_NAME COLUMN_TYPE ALGORITHM=[ COPY | INPLACE |INSTANT ];
MySQL DDL 在操作时会经历三个阶段:准备阶段、执行阶段、提交阶段,不同算法在不同阶段分别做了不同的处理。
下面介绍一下这三种算法的区别:
COPY算法:
会在 SERVER 层加锁,生成临时表,将原表的数据逐行 copy 到临时表中,此时会阻塞 DML 操作,因此 COPY 算法产生的时OFFLINE DDL。COPY 算法的三个阶段分别做了如下操作:
准备阶段:
-
对表的元数据加共享锁,从 *.frm 文件读取表的元数据,此时其它并发的 DDL 不能执行,DML可以执行。
-
共享锁升级为排他锁,此时 DDL 和 DML 都不能执行。
-
在 SERVER 层通过 CREATE TABLE … LIKE … 语句创建临时表,在存储引擎层也生成对应的 *.ibd 和 *.frm 文件。
执行阶段、提交阶段:
-
修改临时表元数据。
-
copy 原表数据到临时表。
-
重命名临时表及文件。
-
删除原表及文件。
-
提交事务,释放锁。
INPLACE算法:
不会创建临时表,部分情况需要 IN-PLACE 的方式 rebild 表。会在准备阶段和提交阶段加元数据锁,执行阶段不会阻塞DML。INPLACE 算法的三个阶段分别做了如下操作:
准备阶段:
-
对表加元数据锁,从共享锁升级为排他锁,此时并发 DML 不能操作。
-
根据语句不同判断 rebuild 表或者 no-rebuild 表。如果是 no-rebuild 会在原表路径下创建 *.frm 和 *.ibd 的临时中转文件。no-rebuild 除创建二级索引外只创建 *.frm 文件;在创建二级索引时,不会生成 *.ibd 文件,但会在原 *.ibd 文件中进行修改,该操作会在参数 tmpdir 指定的路径下生成临时文件,用于存储索引排序结果,然后再合并到原 *.ibd 文件中。
-
如果是 rebuild 则会申请 row log 空间,用于存放 DDL 执行阶段并发执行的 DML 操作,若是 no-rebuild 则不会进行此操作。
执行阶段:
-
释放排他锁,保留元数据共享锁,此时并发 DML 可以执行。
-
扫描元表主键以及二级索引的所有数据页,生成 B+TREE 存储到临时文件中。
-
如果是 rebuild 则将所有对原表的 DML 操作记录在 row log 文件中。
提交阶段:
-
升级元数据锁从共享锁升级成排他锁,此时 DML 不能执行。
-
若是 rebuild 重做 row log 文件中的内容,no-rebuild 则无此操作。
-
重命名原表文件,将临时表名改为原表名,删除原表文件。
-
提交事务,完成变更。
INSTANT算法:
该算法是在 MySQL 8.0.12 版本的新特性,该算法在操作时只修改数据字典中的元数据,不会 copy 数据也不会 rebuild 表,不会加元数据排他锁,原表数据不受影响,不会阻塞 DML ,整个过程瞬间完成。只有在后期触发时才会操作原表。当前版本的 InnoDB 存储引擎支持的 INSTANT 算法的操作有:
-
ADD COLUMN
-
ALTER TABLE TABLE_NAME ADD/DROP INDEX INDEX_NAME(COLUMN)
-
ALTER TABLE TABLE_NAME RENAME NEW_TABLE_NAME
-
设置/删除默认值
-
添加/删除虚拟列
补充:rebuild 是指在 SERVER 层使用 CREATE TABLE LIKE 创建表的行为,no-rebuild 表示不在 SERVER 层通过 CREATE TABLE LIKE 创建表,但是有可能在存储引擎层创建转储的 *.ibd 文件和 *.frm 文件。
【MySQL】Online DDL详解