alter table modify 大概率会丢失数据,尤其缩窄类型、字符集不兼容时会静默截断或转极值,且重设默认值和null属性;change需重复写字段名,inplace不总适用,enum/set修改易致语义错误。

ALTER TABLE MODIFY 会丢失数据吗?
大概率会,尤其是从宽类型缩窄、或字符集/排序规则不兼容时。MODIFY 不是“改个声明”那么简单,MySQL 实际上会重建字段对应的数据列——底层可能触发表拷贝(尤其在 ROW_FORMAT=COMPACT 或使用 ALGORITHM=COPY 时)。比如把 VARCHAR(255) 改成 VARCHAR(10),超长值会被截断且**不报错**(除非开了 STRICT_TRANS_TABLES),已有数据就静默丢了。
- 数值类型缩小时(如
INT→TINYINT),超出范围的值变成该类型的极值(如128变成127) - 字符类型缩小时,末尾被截断,无警告(
sql_mode里没开STRICT_TRANS_TABLES的话) -
MODIFY会重设默认值和 NULL 属性,原字段的DEFAULT和NULL/NOT NULL状态必须显式重写,否则变成NULL+ 无默认
MODIFY 和 CHANGE 有什么实际区别?
只改类型不改名,用 MODIFY;要同时改名+改类型,必须用 CHANGE。但关键陷阱在于:CHANGE 后面**必须重复写一遍新字段名**,哪怕和旧名一样——少写或写错就直接报错 ERROR 1064。
-
ALTER TABLE t MODIFY COLUMN c INT UNSIGNED;—— 安全,只改类型 -
ALTER TABLE t CHANGE COLUMN c c INT UNSIGNED;—— 看似冗余,但这是语法强制要求 -
ALTER TABLE t CHANGE COLUMN c d INT UNSIGNED;—— 字段名从c变成d,连带改类型 - 误写成
ALTER TABLE t CHANGE COLUMN c INT UNSIGNED;(漏掉第二个字段名)→ 直接语法错误
线上表改字段类型怎么避免锁表太久?
MySQL 5.6+ 默认用 INPLACE 算法,但并非所有 MODIFY 都能免锁。比如改 TEXT 到 VARCHAR、或跨字符集(utf8mb4 → utf8),仍会退化为 COPY,整表加 SX 锁,DML 阻塞。
- 先查当前算法支持:
SELECT @@innodb_online_alter_log_max_size;,确保足够大(默认 128M,大表可能不够) - 用
ALTER TABLE ... ALGORITHM=INPLACE, LOCK=NONE;显式声明,失败时立刻报错,不硬扛 - 对大表,优先考虑
pt-online-schema-change工具,它用影子表+触发器,业务几乎无感 - 避开高峰执行,哪怕只是
MODIFY,也建议在低峰期跑,并监控SHOW PROCESSLIST中的copy to tmp table状态
修改 ENUM 或 SET 类型字段要注意什么?
MODIFY 对 ENUM/SET 是高危操作:增删枚举值看似安全,但 MySQL 内部用整数存储顺序索引,一旦调整顺序或删除中间值,原有数据映射会错乱。
- 只允许在末尾追加新值(如
ENUM('a','b') → ENUM('a','b','c')),老数据不受影响 - 删除某个枚举值(如去掉
'b'),原存'b'的行会变成空字符串或NULL(取决于是否允许 NULL) - 重排枚举顺序(如
ENUM('a','b') → ENUM('b','a')),原来存'a'(索引 1)的行,会变成'b'(新索引 1)——数据语义彻底翻车 - 稳妥做法:先导出数据 → 新建字段 → 迁移映射 → 删除旧字段 → 改名
复杂点在于,MODIFY 看似一行命令,但背后牵扯存储格式、索引重建、事务日志膨胀、甚至复制延迟。别信“小字段随便改”,先看 SHOW CREATE TABLE 和 SELECT COUNT(*),再决定要不要动手。











