0、导读
-
MySQL 5.6里,按理说是可以支持Online DDL的,为啥在给一个表增加字段/增加索引时,却把该表上的DML给阻塞了呢?
- MySQL 5.6里,按理说是可以支持Online DDL的,为啥在给一个表增加字段/增加索引时,却把该表上的DML给阻塞了呢?
1、问题
我的朋友小明,在使用Percona 5.6.30版本,想要对一个表增加辅助索引,想着MySQL 5.6版本的Online DDL功能应该比较强大了,不会有啥问题吧,就放心的提交 DDL 命令了,结果悲剧了,后续的 DML 都被阻塞了,看下现场:
小明当时就懵逼了,不是说MySQL 5.6里,增加字段/增加索引的DDL是可以Online的吗,为毛他提交的DDL就把DML给阻塞了呢。无奈之中小明又找到我来求助了~
2、排查
-
看了上面的 图.1,不知道各位看官有没有觉得哪里不对劲呢?先按下不表。
-
-
在MySQL 5.6中,提交DDL命令后,正常的话,该线程状态应该是altering table 、committing alter table to storage engine 这样的才对,为啥是 copy to tmp table 呢,说明这个 DDL 不是IN-PLACE的。
-
-
我们先看下这三种状态分别怎么解释的:
-
-
altering table
-
-
The server is in the process of executing an in-place ALTER TABLE.
-
-
committing alter table to storage engine
-
-
The server has finished an in-place ALTER TABLE and is committing the result.
-
-
copy to tmp table
-
-
The thread is processing an ALTER TABLE statement. This state occurs after the table with the new structure has been created but before rows are copied into it.
-
-
光看线程状态解释好像还是不甚明了,于是让小明干脆在测试环境再尝试模拟增加索引,然后查看线程状态,还是 copy to tmp table。不过测试表数据量比较大,增加索引过程比较久,小明没啥耐心,就按了CTRL-C 把 DDL 命令给终止了,然后终端提示下面的信息:
-
看了上面的 图.1,不知道各位看官有没有觉得哪里不对劲呢?先按下不表。
-
-
在MySQL 5.6中,提交DDL命令后,正常的话,该线程状态应该是altering table 、committing alter table to storage engine 这样的才对,为啥是 copy to tmp table 呢,说明这个 DDL 不是IN-PLACE的。
-
-
我们先看下这三种状态分别怎么解释的:
-
-
altering table
-
-
The server is in the process of executing an in-place ALTER TABLE.
-
-
committing alter table to storage engine
-
-
The server has finished an in-place ALTER TABLE and is committing the result.
-
-
copy to tmp table
-
-
The thread is processing an ALTER TABLE statement. This state occurs after the table with the new structure has been created but before rows are copied into it.
-
-
光看线程状态解释好像还是不甚明了,于是让小明干脆在测试环境再尝试模拟增加索引,然后查看线程状态,还是 copy to tmp table。不过测试表数据量比较大,增加索引过程比较久,小明没啥耐心,就按了CTRL-C 把 DDL 命令给终止了,然后终端提示下面的信息:
咦,好像疑点更多了。
我问小明这个实例是怎么来的,是不是从旧版本数据文件直接拷贝过来用的。经提醒,小明才道出这个实例的数据库文件原来是在MariaDB 5.5环境下运行的,后来直接升级到MariaDB 10.0,再后来为了兼容 GTID 问题(MariaDB和官方 GTID 不兼容这点是挺麻烦的),所以把版本切换成 Percona 5.6.30。
-
现在终于明白了,原来是因为旧版本的数据文件中,存在着 TIME、DATETIME、TIMESTAMP 数据类型,从MySQL 5.6开始,这几个数据类型底层存储格式发生了变化(增加了对毫秒的支持)。
-
- 所以,MySQL发现该表中,存在旧格式的 DATETIME 列,就需要强制进行升级,也就没办法执行 IN-PLACE 的 DDL 了,才有了后面的 DML 锁等待。
关于从旧版本升级到MySQL 5.6及以上,几个注意事项请查阅官方文档说明:
点击(此处)折叠或打开
-
http://dev.mysql.com/doc/refman/5.6/en/checking-table-incompatibilities.html
- http://dev.mysql.com/doc/refman/5.6/en/upgrading-from-previous-series.html
回过头来再说上面提到的 copy to tmp table 状态,就是要因为需要升级数据结构,所以需要重建整张表。
3、解决
-
问题找到了,解决问题的办法也得想到才行呀。方法有三,暴力的 和 非暴力的。
-
-
先说下暴力的吧,其实和本例差不多,就是强制执行一次DDL,让表结构升级下,这个过程是不支持 IN-PLACE 的,必须重建整张表。比如官方推荐的方法之一:
-
-
ALTER TABLE tbl_name FORCE;
-
-
还有一种就是用 mysqldump 把数据从旧版本中备份出来,再在新版本环境中导入加载,效率和第一种不相上下。
-
-
再说下非暴力的,这是从MySQL 5.6.24才引入的功能,新增了一个 avoid_temporal_upgrade 选项,其作用是让我们能选择是否强制升级表结构,看看该选项的描述:
-
-
This variable controls whether ALTER TABLE implicitly upgrades temporal columns found to be in pre-5.6.4 format (TIME, DATETIME, and TIMESTAMP columns without support for fractional seconds precision). Upgrading such columns requires a table rebuild, which prevents any use of fast alterations that might otherwise apply to the operation to be performed.
-
-
-
This variable is disabled by default. Enabling it causes ALTER TABLE not to rebuild temporal columns and thereby be able to take advantage of possible fast alterations.
-
-
-
This variable was added in MySQL 5.6.24. It is deprecated and will be removed in a future MySQL release.
-
-
-
简言之,如果我们不想让MySQL强制升级的话,启用这个选项即可。最后祝各位升级好运 :)
-
问题找到了,解决问题的办法也得想到才行呀。方法有三,暴力的 和 非暴力的。
-
-
先说下暴力的吧,其实和本例差不多,就是强制执行一次DDL,让表结构升级下,这个过程是不支持 IN-PLACE 的,必须重建整张表。比如官方推荐的方法之一:
-
-
ALTER TABLE tbl_name FORCE;
-
-
还有一种就是用 mysqldump 把数据从旧版本中备份出来,再在新版本环境中导入加载,效率和第一种不相上下。
-
-
再说下非暴力的,这是从MySQL 5.6.24才引入的功能,新增了一个 avoid_temporal_upgrade 选项,其作用是让我们能选择是否强制升级表结构,看看该选项的描述:
-
-
This variable controls whether ALTER TABLE implicitly upgrades temporal columns found to be in pre-5.6.4 format (TIME, DATETIME, and TIMESTAMP columns without support for fractional seconds precision). Upgrading such columns requires a table rebuild, which prevents any use of fast alterations that might otherwise apply to the operation to be performed.
-
-
-
This variable is disabled by default. Enabling it causes ALTER TABLE not to rebuild temporal columns and thereby be able to take advantage of possible fast alterations.
-
-
-
This variable was added in MySQL 5.6.24. It is deprecated and will be removed in a future MySQL release.
-
-
- 简言之,如果我们不想让MySQL强制升级的话,启用这个选项即可。最后祝各位升级好运 :)