MySQL 5.6+ 修改字段类型是否锁表取决于是否触发COPY算法:MODIFY仅改类型成功率高,CHANGE即使不改名也按“删+加”处理易降级;跨字符集或缩容必锁表,需用pt-osc规避风险。

MySQL 5.6+ 支持部分字段类型修改免锁,但「能跑通」不等于「真安全」——是否锁表取决于类型变更是否触发 COPY 算法,而 MySQL 从不主动报错告诉你它悄悄降级了。
MODIFY 和 CHANGE 的实际行为差异
MODIFY 和 CHANGE 都会尝试走 INPLACE 算法,但底层逻辑不同:
-
MODIFY COLUMN c TINYINT:只改类型,不改名,InnoDB 可复用原列存储结构,成功率更高 -
CHANGE COLUMN c c TINYINT:语法强制要求写两次字段名,MySQL 内部仍按“删列+加列”处理,哪怕名字没变,也可能退化为COPY - 误写成
CHANGE COLUMN c TINYINT(漏第二个字段名)→ 直接报ERROR 1064 (42000),语法错误,不是锁表问题 - 跨字符集(如
utf8→utf8mb4)或长度收缩(VARCHAR(255)→VARCHAR(10))必然触发COPY,整表加SX锁,DML 全阻塞
如何预判会不会锁表?别信 ALGORITHM=INPLACE
显式写 ALGORITHM=INPLACE, LOCK=NONE 是好习惯,但它只是“请求”,MySQL 会静默降级且不报错。真正可靠的判断方式是:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 查当前支持范围:
SELECT @@innodb_online_alter_log_max_size,大表需 ≥ 512M(默认 128M 容易溢出导致退化) - 用
SELECT COUNT(*)和SELECT AVG(LENGTH(c))看数据实际分布,避免因平均长度小就误判可收缩 - 对千万级表,执行前先在测试库用
EXPLAIN FORMAT=JSON ALTER TABLE t MODIFY c BIGINT(MySQL 8.0.19+ 支持),看输出中"alter_algorithm": "INPLACE"是否为真 - 若报
ERROR 1846 (HY000): ALGORITHM=INPLACE is not supported,说明必须重建,立刻停手,切到pt-online-schema-change
大表改字段类型,为什么 pt-osc 比原生命令更可靠?
pt-online-schema-change 不依赖 MySQL 的在线 DDL 能力,而是用影子表 + 触发器兜底,规避了算法降级风险:
- 它自动检查主键/唯一索引是否存在,没有就拒绝执行,避免数据同步错乱
- 拷贝数据是分 chunk 进行的,默认每批 1k 行,配合
--max-load="Threads_running=25"动态控压 - rename 切换瞬间只持有一个极短的元数据锁(
MDL),通常 - Java 应用需提前关闭 Hibernate 自动建表校验:
spring.jpa.hibernate.ddl-auto=none,否则它会扫information_schema把影子表(如_t_new)当非法表报错 - 注意:原表已有触发器时,
pt-osc无法工作,得先清理或换用gh-ost
真正危险的不是“改不了”,而是“以为没锁,其实锁了两小时”。线上操作前,永远先看 SHOW PROCESSLIST 里有没有 copy to tmp table 或 Waiting for table metadata lock,再决定是继续还是切工具。

















