MySQL 5.7+ 扩大 VARCHAR 长度不一定锁表,但若新长度在 utf8mb4 下字节数跨越255(如63→64,252→256字节),必触发COPY全表重建并全程持写锁;需先查字符集、按“长度×4”算字节数,再验证是否越界。

直接说结论:MySQL 5.7+ 扩大 VARCHAR 长度**不一定锁表**,但只要新长度在 utf8mb4 下对应的最大字节数跨越了 255 字节边界(比如从 255→256),就一定会触发 ALGORITHM=COPY 全表重建,全程持写锁。
查清当前字段的字节上限再动手
别只看 VARCHAR(100) 这个数字,要看它在当前字符集下实际占多少字节。utf8mb4 下每个字符最多 4 字节,所以 VARCHAR(63) 最多 252 字节(安全),VARCHAR(64) 就是 256 字节(越界,必锁)。
- 先执行
SHOW CREATE TABLE your_table;确认默认字符集(常见是utf8mb4) - 计算公式:
新长度 × 单字符最大字节数,例如VARCHAR(64)在 utf8mb4 下 = 64 × 4 = 256 - 如果旧值 ≤ 255 且新值 > 255 → 必须 COPY,锁表不可避免
- 如果两者都 ≤ 255 或都 ≥ 256 → 才有可能走
INPLACE
用 ALGORITHM=INSTANT 强制瞬时修改(MySQL 8.0.12+)
INSTANT 是唯一真正不触碰数据页、只改元数据的模式,但仅支持纯长度扩大(不能缩小,不能改字符集,不能有全文索引)。
- 写法:
ALTER TABLE t ALTER COLUMN c SET DATA TYPE VARCHAR(200) ALGORITHM=INSTANT; - 失败会立刻报错,不会静默降级为
COPY,比ALGORITHM=INPLACE更可控 - 注意:如果字段被虚拟列引用、或表有全文索引,
INSTANT会直接拒绝执行
生产环境试跑前必须验证是否真能 INPLACE
加 ALGORITHM=INPLACE, LOCK=NONE 不等于就能成功 —— MySQL 会在执行前校验,不满足条件就报错或自动 fallback(取决于版本和配置)。
- 验证命令:
ALTER TABLE t MODIFY c VARCHAR(255) ALGORITHM=INPLACE, LOCK=NONE; - 观察
SHOW PROCESSLIST:如果状态变成copy to tmp table,说明已退化 - 更可靠的方式是查执行计划:
EXPLAIN FORMAT=JSON ALTER TABLE t ...,看输出里是否有"alter_algorithm": "inplace"和"supports_inplace": true - 哪怕语句通过,也要在低峰期用
SELECT SLEEP(0.1)模拟并发写入,确认 DML 不卡住
真要跨 255 边界,别硬扛,换工具绕开
当必须从 VARCHAR(63) 改成 VARCHAR(64) 这种“1 字节越界”操作时,ALTER TABLE 无解,只能接受锁表或用外部工具。
- 优先杀长事务:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(NOW() - trx_started) > 60;,否则 DDL 会卡在 MDL 等待 - 调低
lock_wait_timeout(比如设为 5),让 DDL 失败快,避免阻塞后续查询 - 大表必须用
pt-online-schema-change:它通过影子表 + 触发器同步数据,业务无感知,但要求主键存在、无外键依赖
最容易被忽略的一点:改字段长度时,MODIFY COLUMN 会重置 NOT NULL、DEFAULT、COLUMN_FORMAT 等属性,不显式写出就会丢;而 ALTER COLUMN ... SET DATA TYPE(8.0.12+)保留原有约束,更安全。


















