RDS MySQL 8.0修改ENUM字段引发锁等待超时问题排查求助
一、为什么新增更长ENUM值无法复现问题?你遗漏了这两点
1. ENUM存储大小的核心影响因素不是值的长度
你之前的排查可能混淆了ENUM的两种“存储属性”:
- 一种是ENUM值本身的字符长度:仅影响单条记录的存储空间,不会触发全表复制;
- 另一种是ENUM索引的存储字节数:MySQL用整数索引存储ENUM值(比如1对应第一个枚举值,2对应第二个),当枚举值数量≤255时用1字节存储,256~65535时用2字节。只有这种索引存储字节数发生变化,才会触发全表复制。
你后续新增更长字符的ENUM值时,枚举值总数未跨越1字节/2字节的阈值,因此不会触发表复制,自然无法复现问题。
2. 排序规则可能让“末尾新增”变成“中间插入”
你的表使用utf8_unicode_ci排序规则,这里有个极易忽略的细节:MySQL处理ENUM列时,会按照排序规则对枚举值做逻辑排序,而非严格遵循你ALTER语句中写的顺序存储。
举个例子:如果原ENUM列表最后一个值是'Z',你新增'a'并写在语句末尾,但utf8_unicode_ci是不区分大小写的排序规则,'a'会被排在'Z'前面——这相当于在枚举列表中间插入值,而非真正的末尾新增。这种情况下,MySQL需要重新映射所有行的ENUM索引值,必须触发全表复制,这才是此次ALTER耗时超1小时的核心原因。
而你后续测试时新增的更长字符,刚好在utf8_unicode_ci排序下属于真正的末尾值,因此不会触发表复制,无法复现问题。
二、锁等待现象的解释
当ALTER TABLE触发全表复制时,即便你指定了ALGORITHM=INPLACE, LOCK=NONE,在复制流程的最后阶段,MySQL需要短暂持有表级排他锁(X锁)来完成新旧表的切换。
你的表是42GB的高读写吞吐大表,全表复制耗时超1小时,期间积累了大量未完成的读写请求。当最后切换锁时,这些请求会排队等待锁资源,一旦等待时间超过innodb_lock_wait_timeout的设置值,就会抛出Lock wait timeout exceeded; try restarting transaction错误。
内容的提问来源于stack exchange,提问作者Tyagi Akhilesh

