MySQL ALTER操作不能保证数据不丢失,必须预先验证长度、数值范围、NULL占比,并启用严格模式测试转换;MODIFY会重置约束和注释,CHANGE用于改名或ENUM/SET变更但更慢;大表应使用pt-online-schema-change避免锁表。

不能保证“不丢失数据”,只能最大限度规避丢失——关键看新旧类型是否兼容、有没有缩容、是否开了严格模式。
先查数据,别急着ALTER
MODIFY或CHANGE执行时会尝试转换现有数据,但不会主动报错提醒你哪些值会出问题。必须自己先验证:
- 查长度风险:
SELECT id, column_name FROM table_name WHERE LENGTH(column_name) > 50;(改VARCHAR(50)前用) - 查数值范围:
SELECT MIN(column_name), MAX(column_name) FROM table_name;(改TINYINT前确认是否全在-128~127) - 查NULL占比:
SELECT COUNT(*) FROM table_name WHERE column_name IS NULL;(改NOT NULL前心里有数) - 开严格模式再试跑:
SET sql_mode = 'STRICT_TRANS_TABLES';,然后SELECT模拟转换,比如SELECT CAST(old_col AS SIGNED) FROM table_name LIMIT 10;
用MODIFY COLUMN时必须写全约束
MODIFY COLUMN不是“只改类型”,它会重置字段所有属性。漏写就丢约束:
- 错:
ALTER TABLE users MODIFY COLUMN age INT;→ 原来的NOT NULL和DEFAULT 0全没了 - 对:
ALTER TABLE users MODIFY COLUMN age INT NOT NULL DEFAULT 0; - 注释也会丢:
COMMENT '用户年龄'必须手动补上 - 含
TEXT/BLOB的表,若Row_format是COMPACT,得先ALTER TABLE t ROW_FORMAT=DYNAMIC;再改类型,否则报错ERROR 1118
什么时候必须用CHANGE COLUMN
只改类型不用CHANGE,但它在两类场景绕不开:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 要改字段名:哪怕只是
name→username,必须用CHANGE COLUMN name username VARCHAR(100) NOT NULL - 改
ENUM/SET:增删值必须用CHANGE(MODIFY在MySQL 8.0+会直接报ER_CANT_CHANGE_ENUM) - 语法强制写两次字段名:
CHANGE COLUMN c c INT合法;CHANGE COLUMN c INT直接ERROR 1064 -
CHANGE比MODIFY慢,因为本质是删列+重建列,大表更耗时
大表改类型怎么减少锁影响
即使MySQL 5.6+支持ALGORITHM=INPLACE,也不是所有类型变更都免锁:
-
TEXT→VARCHAR、跨字符集(utf8mb4→utf8)、ROW_FORMAT不匹配,都会退化为COPY算法,整表SX锁 - 显式声明:
ALTER TABLE t ALGORITHM=INPLACE, LOCK=NONE, MODIFY COLUMN c BIGINT;→ 失败立刻报错,不硬扛 - 千万级以上表,别信
INPLACE,用pt-online-schema-change更稳,它走影子表+触发器,业务几乎无感 - 改完立刻验证索引是否还生效:
EXPLAIN SELECT * FROM t WHERE c = 123;,类型变更可能让隐式转换导致索引失效
真正麻烦的从来不是ALTER TABLE那条语句怎么写,而是你没看见那条被截断的用户名、那个悄悄变成127的超限年龄、或者应用层因TIMESTAMP→DATETIME失去时区转换后多出来的8小时偏差。










