能改,但必须重写完整字段定义(含not null、default、comment等所有约束),否则会隐性丢失;缩窄类型、跨字符集或改enum/json等易静默丢数据或错乱映射。

能改,但必须把原有约束全写出来,否则NOT NULL、DEFAULT、COMMENT都会丢——不是“改类型”本身丢数据,而是你漏写定义导致隐性变更。
MODIFY COLUMN 必须重写完整字段定义
很多人以为ALTER TABLE t MODIFY c VARCHAR(100)只是加长长度,其实它会清空所有约束。原字段是NOT NULL DEFAULT 'N/A' COMMENT '状态',改完后查SHOW CREATE TABLE t就会发现这些全没了。
- 错误写法(丢失约束):
ALTER TABLE user MODIFY status VARCHAR(100); - 正确写法(显式补全):
ALTER TABLE user MODIFY status VARCHAR(100) NOT NULL DEFAULT 'N/A' COMMENT '状态'; - 哪怕只是把
DECIMAL(10,2)改成DECIMAL(12,4),也得带上NOT NULL和DEFAULT,否则字段可能变成允许NULL,下游应用一插就报错
改前必须验证数据兼容性
MySQL 不会主动拦住危险操作,比如把VARCHAR(255)缩成VARCHAR(50),超长值直接截断,连警告都没有(除非开了STRICT_TRANS_TABLES)。
- 查长度风险:
SELECT COUNT(*) FROM t WHERE LENGTH(c) > 50;结果非零就别硬上 - 查数值越界:
SELECT MIN(c), MAX(c) FROM t;对比新类型的取值范围(如TINYINT是-128~127) - 查 emoji 或四字节字符:
SELECT c FROM t WHERE c REGEXP '[\xF0-\xF7][\x80-\xBF]{3}';,若要从utf8mb4切到utf8,这些全变?
大表或敏感类型改字段,别碰 MODIFY/CHANGE
ENUM、JSON、TEXT类字段用MODIFY或CHANGE极易出事:ENUM('a','b','c')里存的'b'实际是整数2,改成ENUM('a','c','b')后,所有'b'全映射成'c';TEXT → MEDIUMTEXT在 MySQL 5.6+ 仍触发全表拷贝锁写入。
- 千万级表优先用
pt-online-schema-change,不锁主表 - 真要手改,先建新表+
INSERT ... SELECT迁移,再原子替换:RENAME TABLE t TO t_bak, t_new TO t; - 改完立刻验证索引是否还生效:
EXPLAIN SELECT * FROM t WHERE c = 'x';,类型变更可能触发隐式转换,让联合索引最左匹配失效
真正麻烦的从来不是语法怎么写,而是改之前没看懂那条数据到底在哪儿被截断、哪个索引悄悄失效、哪次锁表让下游等了三分钟。











