前言:
mysql5.5 以前默认使用copy方式进行ddl,需要通过创建新表,方式进行ddl,是offline的方式,ddl期间不可以读写
1 按照原表的定义创建临时表;
2 对原表进行加写锁;
3 对新的临时表进行ddl操作;
4 将原表中的数据copy到临时表中;
5 释放原表的写锁;
6 将旧表删除,临时表重命名
**online DDL in mysql5.6 **
在mysql5.6版本中,引入了新特性,Fast Index Create,支持更多的alter table语句来避免copy data同时支持了在线上DDL的过程中不阻塞DML操作。
mysql5.6参数设置
innodb_online_alter_log_max_size参数,但是新增索引的时候正常存在io操作
online DDL in mysql5.7
ddl包含了copy和inplace方式,对于不支持online的ddl操作采用copy方式。
对于inplace方式,mysql内部以“是否修改记录格式”为基准也分为两类:
一类需要重建表(重新组织记录),比如optimize table、添加索引、添加/删除列、修改列NULL/NOT NULL属性等;
另外一类是只需要修改表的元数据,比如删除索引、修改列名、修改列默认值、修改列自增值等。Mysql将这两类方式分别称为rebuild方式和no-rebuild方式
online ddl主要包括3个阶段,prepare阶段,ddl执行阶段,commit阶段
Prepare阶段:
创建新的临时frm文件
持有EXCLUSIVE-MDL锁,禁止读写
根据alter类型,确定执行方式(copy,online-rebuild,online-norebuild)
更新数据字典的内存对象
分配row_log对象记录增量
生成新的临时ibd文件
ddl执行阶段:
降级EXCLUSIVE-MDL锁,允许读写
扫描old_table的聚集索引每一条记录rec
遍历新表的聚集索引和二级索引,逐一处理
根据rec构造对应的索引项
将构造索引项插入sort_buffer块
将sort_buffer块插入新的索引
处理ddl执行过程中产生的增量(仅rebuild类型需要)
commit阶段
升级到EXCLUSIVE-MDL锁,禁止读写
重做最后row_log中最后一部分增量
更新innodb的数据字典表
提交事务(刷事务的redo日志)
修改统计信息
rename临时idb文件,frm文件
变更完成
INPLACE 与COPY
ALGORITHM=COPY是MySQL5.5以及之前的方式
ALGORITHM=INPLACE是MySQL5.6引入的方式
COPY算法,由service层创建一个临时表用于copy数据,然后用新表替换旧表(锁表时间长)
INPLACE算法,“原位替换” 其实主要是指在InnoDB内部完成的DDL操作,在InnoDB内部创建临时文件。整个 DDL 过程都在 InnoDB 内部完成。
对于 server 层来说,没有把数据挪动到临时表,是一个“原地”操作,这就是“inplace”名称的来源。
因此对于INPLACE其实分为非重建表和重建表两类方式,非重建表方式直接在原表基础上更新,效率最高;重建表同样需要copy数据(比如新增字段)
rebuild: 很快操作完成,只有获取MDL的时候禁止读写(短暂),之后降级之后不影响读写并发,唯一可能出现问题时唯一索引造成copy期间重放的问题
norebuild: 只修改schema,不涉及数据复制,所以理论全程online,并且速度很快
具体操作在onlineDDL中的体现
mysql DDL:
> 列维护:
> 新增列: inplace rebuild
> 删除列: inplace rebuild
> 修改列:
> 修改列的数据类型:copy
> 扩展字段并超过255字节(utf8则85):copy
> 收缩存储字字段:copy
> 修改列展示长度: inplace norebuild
> 扩展长度并未超过255字节(或者超过255之上操作): inplace norebuild
> 比如: 300 --> 500
> 100 --> 200
ps: 需要考虑字段涉及二级索引特殊情况
> 修改列注释: inplace norebuild
> 修改列的默认值: inplace norebuild
> 索引维护:
> 主键索引:
> 删除索引: copy
> 新增索引: inplace rebuild
> 删除索引: inplace rebuild
> 二级索引:
> 新增索引: inplace rebuild(实际使用的是tmp,可以算norebuild)
> 删除索引: inplace norebuild
> 修改索引名: inplace norebuild
> 表维护:
> 修改存储引擎: copy
> 修改字符集: copy
> 修改表名: inplace norebuild
> 修改表注释: inplace norebuild
> 自增主键:
> 修改普通主键为自增主键: copy
> 修改自增主键为普通主键: copy
> 修改表自增起始值: inplace norebuild