MySQL 5.5版本
在MySQL 5.5版本前,所有DDL操作都使用Copy Table的方式完成,操作过程中原表数据库不允许写入,只能读取,在MySQL 5.5版本中引入FIC(Fast index creation)特性。
FCI特性:
FCI 操作流程: (1)对表加共享S锁,允许其他会话读操作,但禁止写操作, (2)根据当前表数据创建索引, (3)新索引创建完成,解除S锁,允许读写。 FCI 优点: (1)创建索引不需要拷贝整表数据,创建速度快, (2)创建索引过程中,可以快速中止。 FCI限制: (1)FCI特新仅限于非聚集索引,不试用于聚集索引, (2)索引创建期间,表只允许读不允许写。
在MySQL 5.6.7版本前,DDL操作主要有copy和inplace两种方式,两种方式全程都需要锁表禁止写操作,允许部分时间段的读操作,inplace方式仅支持添加和删除索引两种方式。
copy方式: (1)新建带索引的临时表 (2)锁原表,禁止DML,允许查询 (3)将原表数据拷贝到临时表(无排序,一行一行拷贝) (4)进行rename,升级字典锁,禁止读写 (5)完成创建索引操作 inplace方式: (1)新建索引的数据字典 (2)锁表,禁止DML,允许查询 (3)读取聚集索引,构造新的索引项,排序并插入新索引 (4)等待打开当前表的所有只读事务提交 (5)创建索引结束
MySQL 5.6 版本
在MySQL 5.6.7版本后,引入了row_log来记录DDL期间写操作所产生的日志,因此除DDL操作开始和结束的两小段时间需要对表持EXCLUSIVE-MDL锁禁止读写外,其余DDL操作阶段允许其他回话对表进行读写,因此可算作ONLINE DDL。
对于ONLINE DDL操作,同样包含copy和inplace方式,而对于inplace方式,又可以细分为rebuild方式和no-rebuild方式,rebuild方式指需要重新组织记录的操作如添加删除列或交换列顺序等操作,而no-rebuild方式指不会导致记录格式发生变化的操作如删除和添加索引。
ONLINE DDL可分为三个阶段操作:
Prepare阶段: 1.创建新的临时frm文件 2.持有EXCLUSIVE-MDL锁,禁止读写 3.根据alter类型,确定执行方式(copy,online-rebuild,online-norebuild) 4.更新数据字典的内存对象 5.分配row_log对象记录增量 6.生成新的临时ibd文件 ddl执行阶段: 1.降级EXCLUSIVE-MDL锁,允许读写 2.扫描old_table的聚集索引每一条记录rec 3.遍历新表的聚集索引和二级索引,逐一处理 4.根据rec构造对应的索引项 6.将构造索引项插入sort_buffer块 6.将sort_buffer块插入新的索引 7.处理ddl执行过程中产生的增量(仅rebuild类型需要) commit阶段 1.升级到EXCLUSIVE-MDL锁,禁止读写 2.重做最后row_log中最后一部分增量 3.更新innodb的数据字典表 4.提交事务(刷事务的redo日志) 5.修改统计信息 6.rename临时idb文件,frm文件 7.变更完成
MySQL 5.6版本中各类操作:
仅需要修改元数据的DDL操作: (1)设置列默认值 (2)设置自增列的自增值 (3)删除索引 可以采用Online no-rebuild方式的DDL操作: (1)添加索引 可以采用Online rebuild方式的DDL操作: (1)添加列 (2)删除列 (3)交换列顺序 (4)修改列NULL-NOTNULL属性 (5)修改表ROW-FORMAT (6)添加修改主键 只能采用Copy方式的DDL操作: (1)修改列类型 (2)转换字符集 (3)Optimize table (4)删除主键
PS: 从MySQL 5.6.17版本后,Optimize table可以采用Inplace方式操作。
MySQL 5.6版本Online DDL特性:
Online DDL期间产生Row Log会按照Block来存放和处理,回放Row Log时按照Block来处理,一个Block回放完后处理下一个Block,只有到达最后一个Block时才会锁表,保证最后一个Block完成后新数据和老数据保持一致,因此Online DDL期间产生大量Row Log不会导致表被长时间锁定。 Online DDL操作相关参数: (1)innodb_sort_buffer_size:用来存放Row log的Block大小由参数innodb_sort_buffer_size控制。 (2)innodb_online_alter_log_max_size:控制整个DDL期间产生Row log的文件上限值,当产生的Row Log超过该上限值,则DDL操作失败,并回滚该期间所有未提交的并发DML操作。 (3)innodb_sort_buffer_size:在DDL执行期间Row Log会写入到一个日志文件,该日志文件每次按照innodb_sort_buffer_size来扩展。 (4)old_alter_table,当该参数被启用后,所有Alter操作将使用COPY方式操作。 唯一索引的BUG: (未找到该BUG出处)MySQL 在处理Row Log的时候存在BUG,会导致创建的唯一索引中可能存在不唯一KEY值的情况。
Duplicate entry问题: 在进行Online DDL操作过程中,可能遇到Duplicate entry的报错,但数据和修改命令都正常,该问题解释: When running an online DDL operation, the thread that runs the ALTER TABLE statement applies an “online log” of DML operations that were run concurrently on the same table from other connection threads. When the DML operations are applied, it is possible to encounter a duplicate key entry error (ERROR 1062 (23000): Duplicate entry), even if the duplicate entry is only temporary and would be reverted by a later entry in the “online log”. This is similar to the idea of a foreign key constraint check in InnoDB in which constraints must hold during a transaction. 连接:https://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-limitations.html
MySQL 5.7版本
在MySQL 5.7版本中,增加以下新功能:
1、支持修改索引名操作
操作语法:ALTER TABLE t1 RENAME INDEX idx1 to idx2; 该操作仅需要修改元数据信息和刷新缓存,因此修改操作能快速完成。
2、支持在线增加VARCHAR列的长度
在Innodb存储引擎中,字节长度小于255的列使用1个字节来标识列长,而对于字节长度超过255的列需要使用2个字节来标识列长。 1、如果VARCHAR列长度仅在0-255或255-65535区间发生变化时,仅需要修改元数据信息而不需要对表进行Inplace操作,因此修改操作能快速完成。 语法:alter table tb002 ALGORITHM=INPLACE, CHANGE COLUMN c4 c4 varchar(500); 或: alter table tb002 ALGORITHM=INPLACE, modify c4 varchar(600); 2、如果VARCHAR列长度从0-255区间变化到255-65535区间,则只能使用COPY方式,不允许并发DML。 3、如果缩小VARCHAR列的长度,也只能使用COPY方式,不允许并发DML。
3、支持使用INPLACE方式增加主键
语法:ALTER TABLE tb002 ADD PRIMARY KEY(id),ALGORITHM=INPLACE;
MySQL DDL总结
虽然MySQL 5.6和5.7版本提供了Online DDL操作,但Online DDL仍存在以下问题: (1)主从复制延迟,只有主库上DDL执行成功才会写入到binlog中,而DDL操作在从库上不能并发执行,因此即使主库执行DDL时允许并发DML操作,对于大表操作,仍会引发严重的复制延迟。 (2)主库执行Online DDL时,不能根据负载暂停DDL操作。 (3)使用Inplace方式执行的DDL,发生错误或被KILL时,需要一定时间的回滚期,执行时间越长,回滚时间越长。 (4)使用Copy方式执行的DDL,需要记录过程中的undo和redo日志,同时会消耗buffer pool的资源,效率较低,优点是可以快速停止。 (5)Online DDL并不是所有时间段的Online,在特定时间段需要加元数据锁或其他锁。 (6)允许并发DML的DDL,可能会导致Duplicate entry问题。
MySQL DDL建议
1、对于并发操作较高的表,无论表数据量多少,不能在业务高峰期操作, 2、对于大表和较大表,如果对复制延迟和主库性能敏感,建议改为gh-ost或pt-osc工具, 3、对于包含唯一索引创建的DDL,不能使用gh-ost或pt-osc工具, 4、能业务低峰期操作的DDL,都尽量安排在业务低峰期进行。