mysql 8.0.12+ 中真正在线的 modify/change 操作仅限:varchar 长度扩展(如 50→100)、tinyint→smallint 等兼容类型扩展、8.0.22+ 的 text/blob 长度扩展、移除 default 值;而 int→bigint、varchar→text、not null↔null 切换等多数会触发表拷贝,即使指定 algorithm=inplace。

MySQL 8.0.12+ 支持部分字段类型变更的在线 DDL,但不是所有修改都真正“无锁”——关键看是否触发表重建。
哪些 ALTER TABLE MODIFY/CHANGE 操作能真正在线执行?
MySQL 的 ALGORITHM=INPLACE 并不等于“零影响”。只有满足以下条件的操作才可能全程不阻塞写入(即仅需短暂的元数据锁):
-
MODIFY COLUMN或CHANGE COLUMN仅调整长度(如VARCHAR(50)→VARCHAR(100)),且目标类型与原类型兼容(同为VARCHAR、TINYINT→SMALLINT等) - 扩展
TEXT/BLOB列长度(仅限 MySQL 8.0.22+) - 移除列的
DEFAULT值(但添加DEFAULT会触发重建) - 注意:
INT→BIGINT、VARCHAR→TEXT、NOT NULL↔NULL切换,绝大多数情况会触发表拷贝,即使指定了ALGORITHM=INPLACE
如何判断你的 ALTER 是否真的在线?
执行前加 SHOW ENGINE INNODB STATUS\G 观察 ROW OPERATIONS 区域;执行中查 performance_schema.table_lock_waits_summary_by_table;更直接的是在另一个会话跑:
SELECT * FROM information_schema.INNODB_TRX WHERE trx_query LIKE '%ALTER%';
如果看到 trx_state = 'RUNNING' 且 trx_operation_state 长时间停留在 "adding foreign keys" 或 "copying to tmp table",说明已降级为拷贝模式。此时写入会被阻塞,直到拷贝完成。
安全修改字段类型的实操建议
不要依赖 ALGORITHM=INPLACE 参数强行指定——MySQL 会自行降级,且不报错。更稳妥的做法是:
- 先用
SELECT COUNT(*)和SELECT AVG(LENGTH(col))评估列数据实际分布,避免盲目扩长 - 对大表,在业务低峰期执行,并设置
LOCK=NONE(MySQL 5.6.17+),若报错ERROR 1846 (HY000): ALGORITHM=INPLACE is not supported...,说明必须重建,立刻停止并改用 pt-online-schema-change - 禁止在从库上直接执行
ALTER,主从延迟可能因 DDL 被放大;GTID 模式下,从库会等主库 DDL 完成才继续复制,风险更高 - 测试环境务必用真实数据量验证:用
CREATE TABLE t_copy AS SELECT * FROM t LIMIT 1000000;模拟后压测
为什么 VARCHAR(255) 改成 VARCHAR(191) 很容易失败?
这看似只是缩小长度,但 InnoDB 行格式(尤其是 COMPACT 或 REDUNDANT)要求变长列总长度不能超过页内限制。如果该列是联合索引的一部分,或表启用了 innodb_large_prefix=OFF(默认 MySQL 5.7),缩小操作反而可能触发重建——因为 MySQL 需重排索引项以适配新长度约束。此时错误日志里会出现 "InnoDB: Cannot downgrade a column length in a compressed table" 类提示。











