mysql的一次死锁分析 mysql 5.7 热修改

今天在线上报出了数据库错误:

SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction
搜索这段错误发现mysql发生了死锁,把等待的事务给回滚了。网上有太多死锁的原理,这里就不说了
现象:
回想这次操作,最近一次大操作 执行了 修改表的字段类型,造成了锁表时间比较长,导致正在执行的事务执行时间过长,照成了死锁。
sql语句是通过公司的sql上线平台上线的,原以为运维会给我们做 热修改操作,结果没有才造成了这次执行失败。原来运维也不可信啊。
innodb存储引擎在DDL时执行操作如下:
1. 按照原始表(original_table)的表结构和ddl语句,新建一个不可见的临时表(temporary_table)
2.在原表上面加上WRITE LOCK,阻塞所有的更新操作(insert、delete、update等操作)
3.执行insert into tmp_table select * from original_table
4.rename original_table和tmp_table,最后drop original_table
5.最后释放掉write lock
网上发现如果要解决ddl的同时可以写入操作,解决办法是 使用第三方工具或者自己实现。
方案:
在mysql 5.7之后增加了一个如果是修改varchar 字段大小通过alter table命令,以in-place的方式修改。
VARCHAR 大小可通过 ALTER TABLE语句进行原地(in place)修改,而无需table-copy。如:ALTER TABLE t1 ALGORITHM=INPLACE, CHANGE COLUMN c1 c1 VARCHAR(255);但存在限制,即只支持0~255字节内的或者255以上字节间的增加,也就是说若从254增到256时不能使用INPLACE算法,必须使用COPY算法,否侧报错.这是因为0~255内的VARCHAR值需要一个额外的字节来编码,而256以上的VARCHAR值需要两个字节来编码。另外使用INPLACE算法缩小VARCHAR的ALTER TABLE也是不支持的,必须用COPY算法。

例如 :

sql语句:

Create Table: CREATE TABLE `data1` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `name` varchar(80) NOT NULL DEFAULT '',

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=4652973 DEFAULT CHARSET=utf8


1.对name varchar(80),修改为 name varchar(256)是不行的。

ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.

2. 对name varchar(80),修改为 name varchar(79)是不行的。

ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.

3.对于name varchar(80),修改为 name varchar(86)是不行的。

ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.

修改为100和86 就报错修改为85就没问题  官方文档不是说0-255 只要存储的比特没变就可以吗? 为啥这里不行呢?
其实官方文档是对的! 因为英文没错,但是换成其他字符集的话 存储占位不同。
一个中文字符集占位UTF8 是三个bit  
85*3=255 所以修改为85 可以修改为86 就超过了255 了只能通过copy 的方式了
性能:
表里面有 465.2 w 的数据

普通的alter 修改name的长度,因为mysql会根据当前是否满足 是 inplace条件自动执行的,所以要加上强制的 copy才能看出效果

Query OK, 4194307 rows affected (34.49 sec)

执行了  34.49 sec

满足条件的 inplace

Query OK, 0 rows affected (0.01 sec)

只需要 0.01 sec


在线交流