1引言
传统的DDL中,多数的ALTER TABLE操作是通过创建一个满足需求的新表,之后拷贝数据到新表,再用新表替换旧表.整个过程表加read锁,不支持并发的DML.繁忙的生产系统上对此类DDL的接受程度极低,何解??
MySQL5.5和5.1版本中,以 InnoDB Plugin方式,优化了CREATE INDEX和DROP INDEX,避免了这种数据拷贝开销,详见Fast Index Creation.
MySQL 5.6开始增强了对多种ALTER TABLE操作的类型的支持,避免了这种数据拷贝开销;同时允许在DDL进行时,并发执行的DML操作. MySQL 5.7版本实现了ALTER TABLE RENAME INDEX操作,即支持在线的索引重命名.这些特性的综合,即大家常说的ONLINE DDL.
pt-online-schema-change属于Percona-toolkit工具集(DBA应该很熟悉,有很多nice的工具),通过改进原生ddl的方式,可做到不锁表在线修改表结构,但仍有些使用上应该注意的地方.
本文参考官方文档,对MYSQL5.6+的ONLINE DDL及pt-online-schema-change tool作一下总结介绍:
pt-online-schema-change工作过程及使用限制(隐藏的坑)
ONLINE DDL功能概览/实现细节及使用限制
ONLINE DDL VS pt-online-schema-change的选择
2Pt-Online-Schema-Change
快速介绍PERCONA的pt-online-schema-change(下文称pt-osc)的情况:
2.1pt-osc工作过程:
1.创建一个和alter之前的原表A结构一样的空的新表B
2.在新表B执行alter table 语句
3.在原表A中创建基于insert,update,delete的3个触发器
4.以一定块大小(–chunk-time或–chunk-size-limit控制)从原表A向新表B导入数据,该过程中在原表进行的DML操作会通过触发器更新到新表B中, 这里由于replace into和insert ignore 的使用,可以保证数据的一致性
5.数据拷贝完成后,加排他锁,将原表A重命名为OLD,把新表B重命名为原表A的名称.
6.如果涉及参照该表的外键,根据–alter-foreign-keys-method参数的值来进行处理,这里有4个可选值:
auto:自动选择,优先rebuild_constraints,否则drop_swap
rebuild_constraints:这是优先使用的方法,具体会删除在子表上的外键约束并重新建立对新表B的外键参照约束.这里有一个例外,当子表(或多个) 的alter时间大于–chunk-time,这时不会选用rebuild_constraints方式.这里还有一点要注意,新的外键名称会有所改变.
drop_swap:设置FOREIGN_KEY_CHECKS=0,之后DROP原表A,再重全名新表B为A的名称.+里有两个风险+:一是有段时间原表A是还存在的!应用程序如果查询到A,会报错;二是如果由于错误发生,不能成功将新表B重全名为A的名称时,后果是灾难性的,A的数据永久的丢失了!
none:类似于drop_swap,但少了重全名这个阶段,可由DBA手动完成.
7.如果–no-drop-old-table启用,最后会将旧原表删除
2.2.pt-osc有若干使用限制:
原表上不能已有触发器存在
使用pt-OSC会使增加一倍的空间需求,包括索引和数据文件的大小,如果BINLOG_FORMAT为 Row,还会写一份binlog的产量也会增加
pt-osc执行时间一般会较长,因为工具支持–max-load等参数作为空间里负载状态的监控,会动态地调整数据的拷贝速度.
不支持ALTER TABLE语法中的RENAME操作
不能通过 先DROP COLUMN,再ADD COLUMN的方式来重命名,这样会丢失数据。
当声明NOT NULL 时必须提供一个DEFAULT VALUE,工具不会帮忙.
- -charset或许也是一个坑点,需要对编码有清楚认识(我考虑在另一篇尽量通俗地介绍一下编码常见的坑…),或者使用统一的编码,应该是大家足以应对问题的基本准则
3ONLINE DDL
3.1、ONLINE DDL的显著特点
下面再说说ONLINE DDL的情况,它在性能, 并发, 可用性及扩展性等方面,改进了MYSQL 的操作.
ONLINE DDL在进行中时,DML可并发地进行,相比之前的DDL操作,应用程序不再必须在等待表级锁的释放后才能完成数据的操作,这对7*24小时在线的业务意义比较大,你可以在业务低峰做到真正的在线变更.
之前的DDL复制表的方式下,一般至少需要有额外的被操作表大小的空闲磁盘空间,并且表复制时的IO开销也是对MYSQL服务性能造成影响的一个因素.in-place方式可极大的减少对磁盘空间的需求,并且节省了重建表所必需CPU时间.
对于in-place类型的操作,加为更少的数据需要进入BUFFPOOL中,所以避免了之后大量的从BUFFPOOL向磁盘的PURGE操作,也能在一定程度上减少MYSQL性能的降低。
3.2、影响ALTER TABLE 操作的因素:
是否对物理的数据有修改,还是单纯地变更下元数据即可而并不修改表数据本身
是否表的数据量保持不变或是有增长或是会减少
是否对表数据的修改涉及聚簇索引/二级索引
是否涉及任何的外键关系以及foreign_key_checks 启用与否
是否是分区表以及转化成的底层操作是否涉及多个表,这些表上的操作会遵从online DDL的常规规则.
是否表数据必须被复制,是否表可以按"in-place"方式被重建,或两者均有
是否表会涉及auto-increment类型操作
3.3、ONLINE DDL的相关重要名词:
INPLACE:ALTER TABLE后面紧跟的
ALGORITHM
关键字允许的两个值之一,或许可以理解为"就地",避免重建表带来的IO/空间和CPU的开销,如果可能,应该优先被选择.
COPY:ALTER TABLE后面紧跟的
ALGORITHM
关键字允许的两个值之一,即表复制,除以下的一些情形下并发的DML是允许的(值得注意的是,即使是进行了表复制,ONLINE DDL的速度也是比MYSQL5.5快的),其它不支持并发的DML操作.表复制的情况下,由于有BUFFPOOL的使用,空间的需求,日志的产生等因素,其效果不如INPLACE方式.以下情形允许并发的DML:
Adding, dropping, or reordering columns
Adding or dropping a primary key.
Changing the ROW_FORMAT or KEY_BLOCK_SIZE properties for a table.
Changing the nullable status for a column.
OPTIMIZE TABLE
Rebuilding a table with the FORCE option
Rebuilding a table using a “null” ALTER TABLE … ENGINE=INNODB statement
LOCK
选项控制是否锁表及锁的类型,同时也是一种安全性的"断言(ASSERTION)",简单说当你为了更安全地执行DDL,可以使用LOCK
声明可以接受的锁类型,比如为了不中断应用程序对该表的读,你声明了LOCK=None
,恰好你执行的是添加auto-increment的表,alter
语句本身是需要共享锁的,这里"断言"就会失败,并不会真正开始DDL的实际变更.与PERCONA的pt-online-schema-change类似的,ONLINE DDL在开始执行初,会有短暂的排它锁.LOCK=NONE:不阻塞读写
LOCK=SHARED:允许读操作,不允许写操作.
LOCK=DEFAULT:在"尽可能不去锁表"的原则下,mysql来判断lock的实际值.
LOCK=EXCLUSIVE:读写操作都不支持。
3.4、功能概览:
下表是官方给出的执行方式规则,这里作了简单翻译:

简单说明:
基于前面对概念的介绍,很明显,In-Place 为Yes/Copies Table为No/Allows Concurrent DML为Yes,都是应该优先考虑的,会有更好的效率.
带 * 号的Yes或No,应该注意Notes表的说明.
可以适当的"合并"或"拆分"多个DDL语句.大家都知道,5.5及之前,我们应该尽可能地合并多个ALTER TABLE语句为一条来执行,因为涉及复制/重建表仅发生一次,以减少总的执行时间.但这里其实不然,由于In-Place 和Table-Copying带来的处理方式的区别,应该反其道而行,如
ALTER TABLE t1 ADD INDEX i1(c1), ADD UNIQUE INDEX i2(c2),
CHANGE c4_old_name c4_new_name INTEGER UNSIGNED;
拆分为:
ALTER TABLE t1 ADD INDEX i1(c1);
ALTER TABLE t1 ADD UNIQUE INDEX i2(c2);
ALTER TABLE t1 CHANGE c4_old_name c4_new_name INTEGER UNSIGNED NOT NULL;
当然对于多个使用表复制方式的DDL,仍然可用合并方式
3.5、In-Place 对比Table-Copying
一个DDL的性能如何,很大程度上由"是不是以 in-place方式"进行还是需要表复制并重建表决定.In-Place带来的性能提升,适用于二级索引,并不适用聚集索引(主键,数据在物理磁盘上的排列顺序);聚集索引情形下,可以使用ALGORITHM=INPLACE
,只是仍会有表的复制,但性能会比ALGORITHM=COPY
好,因为:
不涉及undo和redo日志
.二级索引是预先有序的,可以顺序加载
不涉及change buffer,不会有随机数据插入二级索引中
当不确定一个DDL的开销时,这里有一个实用的方法辅助判断:
复制目标表的结构到测试表
插入少量的数据到测试表
在测试表上执行目标DDL
检查“rows affected”,非零的值表示该DDL需要重建表,或许有性能上的影响.
3.6、Online DDL条件下如何Crash Recovery
当SERVER崩溃时,尽管不会有数据的丢失,但实际对聚簇索引和二级索引的处理却有很大的不同.
如果是二级索引,在恢复时,MySQL会简单地DROP任何未创建成功的二级索引,你必须重新执行该ALTER TABLE 或 CREATE INDEX
如果是聚簇索引,情况比较复杂一些,因为整个表的数据必须被复制到一个新的聚簇索引中.MYSQL会创建一个临时表A,并且它是按新的聚簇索引方式来定义的.当完成了从原表向临时表A的数据复制,将原表 RENAME为另一临时表B,接着RENAME临时表A为新的表(表名同原表),最后DROP临时表B
3.7、online ddl实现原理可参见这里
http://www.cnblogs.com/cchust/p/4639397.html
3.8、Online DDL 与分区表
对分区表执行的ALTER TABLE操作,遵守上表的规则,并且不执行与非分区表相同的API.分区类型执行ALTER TABLE语句,只允许使用ALGORITHM=DEFAULT
和LOCK=DEFAULT
当对分区表执行修改分区相关的ALTER TABLE语句时,会使用COPY方式进行;当对分区表执行的ALTER TABLE 语句不涉及分区相关的调整时,会使用INPLACE方式进行,值得注意的是,即使是INPLACE 方式,因实际执行是在多个表上,仍可能造成性能的波动.
对于分区方式是RANGE 或 LIST和表,ADD PARTITION 和DROP PARTITION不会复制数据
对于所有类型的表,TRUNCATE PARTITION不会复制数据
对于分区方式是HASH 或 LIST的表,因加只读锁,并发的查询是允许的
对于分区方式是LINEAR HASH 或 LIST的表,REORGANIZE PARTITION, REBUILD PARTITION, or ADD PARTITION or COALESCE PARTITION操作会复制数据,期间加只读锁,允许并发查询
3.9、ONLINE DDL的使用限制
ONLINE DDL在需要进行表复制时,可能使用大量的磁盘空间,即务必使用MYSQL的datadir有足够的可用空间,特别的从MySQL 5.6.29/5.7.11开始,可使用 innodb_tmpdir来配置一个单独的临时目录,专用于online DDL操作.
TEMPORARY TABLE上
的ONLINE DDL会使用COPY
方式,而不是Fast Index Creation
当尝试DROP一个被外键需要的索引时,会产生错误1553
主库上执行的alter table在完成时再写入binlog,所以当从库按顺序应用
relay log时,大的ddl会导致从库产生延迟。(pt-osc可以控制延迟时间,所以这种场景下它更合适)
如果表上存在
ON...CASCADE
或ON...SET NULL
设定,LOCK=NONE
是不被允许的
在ALTER TABLE执行的初始阶段,根据设定的LOCK类型的不同,DDL操作可能需要获取一个排他锁,但这个锁的获得等待可能持续很长的时间,比如当前正存在大的事务在执行;同理一样可能会等待一个大事 务提交后DDL才可获取到招待最后原语所需的排他锁,也可能会持续较长时间.
执行ONLINE DDL的线程,会同时应用由并发执行DML操作的线程产生的“online log”(记录在当前表由其它线程并发的DML操作),当DML操作被提交时,可能会出现"duplicate key entry error",即使冲突的键只是 暂的并且稍后被处理为一致.
全局变量innodb_online_alter_log_max_size控制着online DDL招待期间,
online log
所允许的最大值,默认为128M,可手动调整.
MYSQL5.6之前版本所创建的INNODB表,如果包含时间日期类型的列(DATE,DATETIME,TIMESTAMP),并且未经
ALTER TABLE ...ALGORITHM=COPY
说一句进行重建过,当被招待ALTER TABLE ... ALGORITHM=INPLACE
操作时,会报出如下错误:
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported.Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.
在INNODB类型表上进行的
OPTIMIZE TABLE
操作会转换为ALTER TABLE操作,将会重建表/更新索引数据/释放聚簇索引中未使用到的空间.在MySQL5.7.4之前 ,ONLINE DDL不支持此类操作
对于巨大的表,涉及到table copy时,没有办法暂停这个ddl,或者给IO/CPU的使用加上阈值限制.
从MySQL 5.7.6开始,可以通过
performance schema
提供了监控ALTER TABLE进度信息的能力.
如果DDL执行时间很长,期间又产生了大量的dml操作,以至于超过了
innodb_online_alter_log_max_size
变量所指定的大小,会引起DB_ONLINE_LOG_TOO_BIG
错误。默认为 128M,特别对于需要拷贝大表的alter操作,考虑临时加大该值,以此获得更大的日志缓存空间
4pt-osc VS ONLINE DDL 如何选择
ONLINE DDL在必须出现表复制时效率较低
pt-osc在目标表上已经存在触发器时,不可用
pt-osc对空间的需求较高,为硬性的
修改索引、外键、列名时,优先采用ONLINE DDL,优先指定
ALGORITHM=INPLACE方式
积极采用样本测试执行效率,评估可行性。
后续将单独整理测试数据,待续。

参考:
http://dev.mysql.com/doc/refman/5.7/en/innodb-create-index-overview.html#innodb-online-ddl-summary-grid
http://www.cnblogs.com/cchust/p/4639397.html
https://www.percona.com/doc/percona-toolkit/2.2/pt-online-schema-change.html
以上内容为IPD原创,如需转载,请注明出处~
扫描下方二维码关注我们~IPDCHAT专注输出技术干货~!






