MySQL 5.7中MODIFY COLUMN必然重建表,因其物理存储格式变更(如VARCHAR长度跨字节头阈值、添加NOT NULL DEFAULT、改字符集、整型扩容等)触发引擎层不兼容,直接拒绝INPLACE,强制COPY流程并全程MDL_EXCLUSIVE锁。

MySQL 5.7 修改列属性(如 MODIFY COLUMN、CHANGE COLUMN)几乎必然触发全表重建,不是配置没写对,而是引擎层根本不支持就地修改这类变更。
为什么 MODIFY COLUMN 一定会重建表?
InnoDB 在 5.7 中对列定义变更的判断非常底层:只要字段的物理存储格式发生变化,就必须重建。典型场景包括:
-
VARCHAR(255)→VARCHAR(256):utf8mb4 下前者最多占 1020 字节(255×4),长度头用 1 字节;后者最多 1024 字节,长度头必须升为 2 字节 → 存储结构不兼容 - 添加
NOT NULL DEFAULT 'xxx'到非空表:需逐行回填默认值,无法跳过数据扫描 - 修改字符集(如
CONVERT TO CHARACTER SET utf8mb4):每个字符字节数可能翻倍,行格式重排不可避免 - 从
TINYINT改成INT:固定长度字段扩容,破坏原有页内偏移布局
这些操作在执行前就会被 MySQL 拒绝 ALGORITHM=INPLACE,直接报错 ERROR 0A000: ALGORITHM=INPLACE is not supported,而不是静默降级。
ALTER TABLE CHANGE COLUMN 的真实代价
CHANGE COLUMN 看似只是改个名字,但 MySQL 5.7 内部把它当作「删除旧列 + 新增同名新列」处理,哪怕类型完全一致。后果是:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 所有索引需重建(包括主键聚簇索引)
- 全文索引、空间索引、函数索引全部失效重做
- 触发器、外键约束关联的元数据全部刷新
- 即使只改一个字段名,
SHOW PROCESSLIST也会显示copy to tmp table
这不是“慢”,而是整个流程不可绕过:建临时表 → INSERT INTO ... SELECT 全量拷贝 → 排序构建索引 → 原子 RENAME。期间全程持有 MDL_EXCLUSIVE 锁,任何读写都被阻塞。
怎么提前知道某次 MODIFY 是否会锁死业务?
别靠经验猜,用 MySQL 自己的判断逻辑验证:
- 先跑
EXPLAIN FORMAT=JSON ALTER TABLE t MODIFY c VARCHAR(512),检查输出里是否有"alter_algorithm": "inplace"和"supports_inplace": true—— 缺一不可 - 如果返回
"alter_algorithm": "copy",立刻放弃,别在线上试 - 执行前务必查
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(NOW() - trx_started) > 60,长事务会让 DDL 卡在“等锁”阶段,且默认等一年都不报错 - 用
pt-online-schema-change替代时,注意它不支持含外键或全文索引的表,得先清理依赖
真正危险的不是“会不会锁”,而是“锁多久没人知道”——重建耗时取决于磁盘 IO、buffer pool 命中率、索引数量,而非 SQL 写得有多简洁。线上大表改结构,永远假设它会卡住,然后倒推怎么让卡住不影响用户。

















