mysql 5.6前alter table modify column默认用copy算法,需重建表并全程锁表;5.6+支持inplace但受限于类型兼容性、字符集等,须显式指定algorithm=inplace和lock=none,并验证环境约束。

ALTER TABLE MODIFY COLUMN 为什么会锁表
MySQL 5.6 之前,ALTER TABLE ... MODIFY COLUMN 默认走 COPY 算法:先建新表、逐行拷贝数据、重建索引、删旧表。整个过程原表不可写,DML(INSERT/UPDATE/DELETE)被阻塞,业务直接中断。
即使只改字段类型(比如 VARCHAR(100) → VARCHAR(200)),只要不满足“就地修改”条件,依然会触发全表拷贝。
- 常见触发 COPY 的操作:
MODIFY COLUMN改类型、改长度(部分情况)、加 NOT NULL、删默认值 - INPLACE 不是万能的:它只支持某些类型变更(如
VARCHAR变长扩展、ADD COLUMN末尾加列),且要求引擎为 InnoDB、MySQL ≥ 5.6 - 执行前可查
SHOW CREATE TABLE确认当前字段定义,避免隐式类型转换导致意外降级为 COPY
怎么强制用 ALGORITHM=INPLACE
显式指定算法是控制行为最直接的方式,但不是所有语句都能成功——MySQL 会校验是否真能 inplace,否则报错而不是静默回退。
正确写法是带 ALGORITHM=INPLACE 和 LOCK=NONE(如果支持):
ALTER TABLE users MODIFY COLUMN nickname VARCHAR(255) ALGORITHM=INPLACE, LOCK=NONE;
-
ALGORITHM=INPLACE告诉 MySQL 尽量复用原表结构,只改元数据或做页内调整 -
LOCK=NONE要求全程不锁 DML;若不满足(比如字段有全文索引、或类型变更涉及字符集转换),会报错:ERROR 1846 (HY000): ALGORITHM=INPLACE is not supported... Reason: Cannot change column type INPLACE - 别写
ALGORITHM=COPY来“保险”——那等于主动选择停服,除非你明确要兼容老版本或调试用
哪些 MODIFY 操作实际能 INPLACE 成功
不是所有“看起来只是调个长度”的修改都安全。能否 inplace 取决于底层存储格式(B+Tree 页结构)和类型兼容性。
- ✅ 安全(通常 INPLACE + LOCK=NONE):
VARCHAR(N)→VARCHAR(M)(M > N,且同字符集);TINYINT→SMALLINT(无符号扩展) - ⚠️ 风险(可能 COPY 或需 LOCK=SHARED):
TEXT↔VARCHAR;CHAR↔VARCHAR;改字符集(如utf8mb4→utf8mb4_0900_as_cs) - ❌ 必然 COPY:
INT→VARCHAR;加NOT NULL且字段含 NULL 值;改主键字段类型 - 执行前用
EXPLAIN FORMAT=JSON ALTER TABLE ...(MySQL 8.0+)看alter_algorithm和lock_type字段,比猜靠谱
线上改字段前必须验证的三件事
很多线上事故不是因为语法错,而是没摸清表真实状态和环境约束。
- 查
information_schema.INNODB_TRX和PROCESSLIST,确认没长事务或慢查询正占用该表——INPLACE 虽不锁表,但会等活跃事务结束才能开始元数据锁升级 - 在从库或影子库上跑一遍相同语句,观察
SHOW ENGINE INNODB STATUS中的ALTER TABLE阶段耗时,判断是否真走 INPLACE(看是否有大量copy to tmp table日志) - 检查 binlog_format 是否为
ROW:若为MIXED或STATEMENT,某些 inplace 操作可能被降级为 statement 记录,导致主从不一致
真正麻烦的从来不是语法对不对,而是你改的那个字段,是不是正被某个凌晨跑批的存储过程反复 SELECT ... FOR UPDATE 锁着。这种时候,ALGORITHM=INPLACE 也得干等。











