会丢失数据,主要发生在类型不兼容时:varchar缩容被截断、int改tinyint越界转极值、text转varchar超长丢弃、enum删值致空字符串,且非严格模式下静默发生。

ALTER TABLE MODIFY COLUMN 会丢失数据吗?
直接改字段类型时,MODIFY COLUMN 和 CHANGE COLUMN 都可能丢数据,关键看新旧类型的兼容性。比如把 VARCHAR(10) 改成 VARCHAR(5),超长值会被截断;把 TEXT 改成 VARCHAR(100),超出部分直接丢弃;把 INT 改成 TINYINT,值超过 127 的全变 127 或溢出报错(取决于 SQL mode)。
- 执行前务必用
SELECT检查字段最大长度、是否含 NULL、是否有超出目标范围的值 - 生产环境必须先在测试库跑一遍,观察 warning(用
SHOW WARNINGS查) - 对大表慎用,
MODIFY在 MySQL 5.6+ 默认触发 ALGORITHM=COPY,会锁表重建整张表
什么时候该用 CHANGE COLUMN 而不是 MODIFY COLUMN?
CHANGE COLUMN 和 MODIFY COLUMN 都能改类型,但 CHANGE 必须重写字段名(哪怕名字不变),MODIFY 则不用。实际差异在于:只有 CHANGE 能同时改字段名和类型;而 MODIFY 更轻量,语义更清晰——只动类型不动名。
- 只想改类型,用
ALTER TABLE t MODIFY COLUMN c INT UNSIGNED - 既要改类型又要改名,用
ALTER TABLE t CHANGE COLUMN old_c new_c BIGINT NOT NULL - 如果误写
CHANGE但名字没变,语法合法但多一次字符串比较,无实质影响
修改 ENUM 或 SET 类型字段要特别注意什么?
MySQL 对 ENUM 和 SET 的修改极其敏感。添加新值可以,但删掉已有枚举值会导致对应行数据变成空字符串或 NULL(取决于是否允许 NULL),且无法恢复。
- 加枚举值安全:
MODIFY COLUMN status ENUM('pending','done','archived')(原为ENUM('pending','done')) - 删枚举值危险:原值是
'archived',删掉后该字段值变为空字符串,且不报错 - 改类型时别漏掉
NOT NULL约束——原字段有NOT NULL,新定义里没写,就会变成允许 NULL
大表改字段类型卡住怎么办?
MySQL 8.0.12+ 支持 ALGORITHM=INSTANT,但仅限加字段、删字段、改字段默认值等极少数操作;改数据类型基本都走 COPY 或 INPLACE(后者仍需重建索引)。真正卡住往往是因为锁表时间长或磁盘 IO 压力大。
- 确认当前版本支持的算法:
ALTER TABLE t ALGORITHM=INPLACE, MODIFY COLUMN c DATETIME(部分类型支持 INPLACE) - 避开业务高峰,监控
SHOW PROCESSLIST中状态是否长期卡在copy to tmp table - 考虑用 pt-online-schema-change 工具,它通过双写+触发器实现无锁变更,但要求主键存在且不能有外键依赖
改类型这事,没有“一键安全”的方案。最麻烦的不是语法写错,而是低估了隐式转换、字符集差异(比如 utf8mb4 vs utf8)、以及 timestamp 自动更新行为带来的副作用。动手前花十分钟查 DESCRIBE table 和 SHOW CREATE TABLE table,比事后救数强十倍。











