前言
最近发现有一个780w左右的表的某个字段长度设置不合理,导致数据无法插入 , 于是计划修改长度。 担心会锁表阻塞业务所以选择晚上执行修改, 结果在晚上发现这个修改是秒生效, 并没有阻塞数据库,于是分析下原因。
字段content修改前类型是varchar(255) 字符编码是utf8mb4。 修改成varchar(2048)
MySQL的行存储格式
mysql的每行数据的默认存储格式是dynamic, 但是dynamic格式和compact格式差异不大, 本文以 compact的行格式说明问题, compact的行格式如下:
头部有一个变长字段列表, 其中存储的是这一行中变长字段的长度。
比如我content字段之前是varchar(255). 而utf8mb4每个汉字4个字节表示, content存满后的长度是1020字节, 在头部就需要存储一个数字1020, 所以头部中有两个字节是用来表示content的长度的。
现在我把长度改成了varchar(2048), 修改后存满需要8192字节, 还是只需要两个字节来表示这个长度, 因此每一行记录的变长字段部分不需要修改。
总结
- mysql的compact的行格式中每行头部会开辟对应的空间来存储变长字段长度值。
- 如果修改变长字段的长度 导致行头部已有的空间不够表达字段长度了, 就会修改每一行的头部
- 在修改每一行的头部的时候就会锁住全表。
- 如果修改的字段的长度, 头部现有的空间依旧可以满足变长字段长度的表示需要, 则不会修改每一行数据, 就不会锁表了。