MODIFY COLUMN 或 CHANGE COLUMN 都可能丢数据,是否丢失取决于新旧类型兼容性、SQL mode 设置及数据验证;缩窄VARCHAR、数值越界、隐式转换、DECIMAL精度损失均需提前检查;MODIFY仅改类型,CHANGE可改名+类型,但都需显式重写约束;大表变更应优先用pt-online-schema-change避免锁表。

直接说结论:MODIFY COLUMN 或 CHANGE COLUMN 都可能丢数据,是否丢失取决于新旧类型兼容性、SQL mode 设置、以及你有没有提前验证数据分布——不是语法写对了就安全。
查清现有数据再动手,别信“应该没问题”
改类型前不看数据,等于蒙眼过河。MySQL 不会主动拦你,但会静默截断或转极值。
- 缩窄 VARCHAR:用
SELECT COUNT(*) FROM tbl WHERE LENGTH(col) > 10查超长值(假设要改成VARCHAR(10)) - 数值越界:用
SELECT MIN(col), MAX(col) FROM tbl对比新类型的取值范围(如TINYINT是 -128~127) - 隐式转换风险:把
VARCHAR改成INT?先跑SELECT col FROM tbl WHERE col REGEXP '[^0-9]'看非数字内容 - DECIMAL 精度损失:
DECIMAL(10,2) → DECIMAL(5,2)会砍整数位,用SELECT col FROM tbl WHERE col >= 100000快速扫一遍
MODIFY 和 CHANGE 到底怎么选、怎么写才不踩坑
只改类型不改名,用 MODIFY COLUMN;要改名+改类型,必须用 CHANGE COLUMN。但两者都要求你显式重写约束,漏掉就变默认行为。
-
MODIFY COLUMN不保留原COMMENT,要补上:加COMMENT '说明文字' -
CHANGE COLUMN必须写两次字段名:CHANGE COLUMN old_name old_name INT NOT NULL—— 看似重复,少一个就报ERROR 1064 - 原字段有
DEFAULT或NOT NULL?新定义里不写,就变成NULL+ 无默认值 - 改
TEXT/BLOB类型前,先确认行格式:SHOW TABLE STATUS LIKE 'tbl',若是Compact,得先ALTER TABLE tbl ROW_FORMAT=DYNAMIC
大表改字段,锁表现实很骨感
哪怕加了 ALGORITHM=INPLACE, LOCK=NONE,也不是所有 MODIFY 都能免锁。TEXT/BLOB、跨字符集、ROW_FORMAT 不兼容时,照样全表拷贝。
- 千万级表别硬扛
ALTER,优先用pt-online-schema-change,它靠影子表+触发器,业务基本无感 - 执行中盯紧
SHOW PROCESSLIST,看到copy to tmp table就说明已锁表,立刻评估影响 - 线上环境避开高峰,改完立刻
EXPLAIN SELECT * FROM tbl WHERE col = ?看索引是否还生效 - 改完别忘了检查外键和索引名:字段叫
user_id变成uid后,fk_orders_user_id这种约束名不会自动更新,排查时容易绕晕
真正麻烦的从来不是 ALTER TABLE 怎么写,而是你改完才发现某条订单的金额被截成 0、某个用户昵称少了后三个字、或者联合索引在 WHERE 条件里突然不走了——这些都不会报错,只会慢慢拖垮查询。


















