[TOC]
前言
DDL(Data Definition Language) 众所周知,DDL定义了数据在数据库中的结构、关系以及权限等。比如CREATE,ALTER,DROP等等。
几种算法实现
分别是:copy、inplace、instant。
- copy 算法为最古老的算法,在 MySQL 5.5 及以下为默认算法。
- 从 MySQL 5.6 开始,引入了 inplace 算法并且默认使用。inplace 算法还包含两种类型:rebuild-table 和 not-rebuild-table。MySQL 使用 inplace 算法时,会自动判断,能使用 not-rebuild-table 的情况下会尽量使用,不能的时候才会使用 rebuild-table。当 DDL 涉及到主键和全文索引相关的操作时,无法使用 not-rebuild-table,必须使用 rebuild-table。其他情况下都会使用 not-rebuild-table。
- 从 MySQL 8.0.12 开始,引入了 instant 算法并且默认使用。目前 instant 算法只支持增加列等少量 DDL 类型的操作,其他类型仍然会默认使用 inplace。
copy 算法
较简单的实现方法,MySQL 会建立一个新的临时表,把源表的所有数据写入到临时表,在此期间无法对源表进行数据写入。MySQL 在完成临时表的写入之后,用临时表替换掉源表。这个算法主要被早期(<=5.5)版本所使用。
inplace 算法
从 5.6 开始,常用的 DDL 都默认使用这个算法。inplace 算法包含两类:inplace-no-rebuild 和 inplace-rebuild,两者的主要差异在于是否需要重建源表。
inplace 算法的操作阶段主要分为三个:
- Prepare阶段:- 创建新的临时 frm 文件(与 InnoDB 无关)。- 持有 EXCLUSIVE-MDL 锁,禁止读写。- 根据 alter 类型,确定执行方式(copy,online-rebuild,online-not-rebuild)。更新数据字典的内存对象。- 分配 row_log 对象记录数据变更的增量(仅 rebuild 类型需要)。- 生成新的临时ibd文件 new_table(仅rebuild类型需要)。
- Execute 阶段:降级EXCLUSIVE-MDL锁,允许读写。扫描old_table聚集索引(主键)中的每一条记录 rec。遍历new_table的聚集索引和二级索引,逐一处理。根据 rec 构造对应的索引项。将构造索引项插入 sort_buffer 块排序。将 sort_buffer 块更新到 new_table 的索引上。记录 online-ddl 执行过程中产生的增量(仅 rebuild 类型需要)。重放 row_log 中的操作到 new_table 的索引上(not-rebuild 数据是在原表上更新)。重放 row_log 中的DML操作到 new_table 的数据行上。
- Commit阶段:当前 Block 为 row_log 最后一个时,禁止读写,升级到 EXCLUSIVE-MDL 锁。重做 row_log 中最后一部分增量。更新 innodb 的数据字典表。提交事务(刷事务的 redo 日志)。修改统计信息。rename 临时 ibd 文件,frm文件。变更完成,释放 EXCLUSIVE-MDL 锁。
instant 算法
MySQL 8.0.12 才提出的新算法,目前只支持添加列等少量操作,利用 8.0 新的表结构设计,可以直接修改表的 metadata 数据,省掉了 rebuild 的过程,极大的缩短了 DDL 语句的执行时间。
基于 instant算法 , 可以让 mysql大表加字段做到秒级, 案例:
ALTER TABLE person ADD COLUMN age INT ALGORITHM=instant;