mysql 8.0.12+ 支持 modify/change column 在线执行,但是否真正在线取决于是否触发表重建:扩大varchar长度、调整decimal精度、增删default等可inplace;而text转varchar、改字符集、varchar↔char等必重建表。

MySQL 8.0.12+ 支持 ALTER TABLE ... MODIFY COLUMN 或 CHANGE COLUMN 的大部分操作在线执行(即不阻塞 DML),但是否真正“在线”取决于字段类型变更是否涉及行格式重写、是否需要重建表,以及是否启用 ALGORITHM=INPLACE 和 LOCK=NONE。关键在于理解哪些修改能避免全表拷贝,从而保障业务连续性和存储效率。
哪些字段类型变更可真正在线完成
以下修改通常支持 ALGORITHM=INPLACE 且 LOCK=NONE(需满足引擎为 InnoDB、行格式为 DYNAMIC/COMPACT、无全文索引等前提):
-
扩大字符串长度:如
VARCHAR(50) → VARCHAR(200)(仅修改元数据,不触发行数据重写) -
收缩字符串长度(安全前提下):如
VARCHAR(200) → VARCHAR(100),前提是现有所有值长度 ≤100 —— MySQL 会校验,失败则报错,不会静默截断 -
调整数值类型精度(非改变存储字节):如
TINYINT → SMALLINT不行(字节扩展需重写),但DECIMAL(10,2) → DECIMAL(12,2)可行(仅改元数据) -
添加/删除
DEFAULT值:不改变物理结构,纯元数据操作
哪些修改必然触发表重建(影响性能与可用性)
以下操作无法避免全表扫描与重建,即使指定 ALGORITHM=INPLACE,MySQL 也会自动降级为 COPY:
-
从
TEXT/BLOB改为非大对象类型(如TEXT → VARCHAR(500)):因存储机制不同(溢出页 vs 行内) -
改变字符集或排序规则(如
utf8mb4_0900_as_cs → utf8mb4_unicode_ci):需逐字段转码 -
在
NOT NULL字段上添加默认值(且表非空):旧版本需填充历史行;MySQL 8.0.13+ 对部分场景做了优化,但仍可能锁表 -
将
VARCHAR改为CHAR或反之:定长/变长存储逻辑差异导致重组织
实操建议:安全、高效地执行在线变更
执行前务必验证可行性,并控制风险:
-
先用
ALTER TABLE ... ALGORITHM=INPLACE, LOCK=NONE测试,若报错ALGORITHM=INPLACE is not supported,说明必须重建,应避开业务高峰并准备回滚方案 -
对大表启用
pt-online-schema-change(Percona Toolkit):它通过影子表+触发器实现无锁变更,适合无法使用原生在线 DDL 的场景(如 MySQL 5.7 或复杂变更) -
优化存储性能要结合实际数据分布:例如将频繁更新的
VARCHAR(255)缩小为VARCHAR(64),可减少页分裂和缓冲池压力;但过度收缩易引发后续扩容,需权衡 -
变更后运行
ANALYZE TABLE:更新统计信息,帮助优化器生成更优执行计划
查看变更是否真正在线执行的方法
执行 ALTER TABLE 后,检查 performance_schema.table_lock_waits_summary_by_table 或观察 SHOW PROCESSLIST 中是否有长时间处于 copy to tmp table 状态的线程。更直接的方式是开启慢日志并设置 log_slow_admin_statements = ON,再配合 pt-query-digest 分析 DDL 执行细节。











