ALTER TABLE MODIFY COLUMN 会丢失数据吗
直接用
MODIFY COLUMN改字段类型,是否丢数据,取决于新旧类型的兼容性。比如从
VARCHAR(255)缩成
VARCHAR(10),超长值会被截断;从
INT改成
TINYINT,超出 -128~127 范围的值会变成边界值或报错(取决于 SQL mode)。不是所有修改都安全,尤其涉及长度缩减、精度降低或类型跨大类(如字符串→数字)时。 改宽不丢数据(
VARCHAR(10) → VARCHAR(200)) 改窄大概率丢数据(
TEXT → VARCHAR(100),超长部分被截)
DECIMAL(10,2) → DECIMAL(5,2):整数位不够时,插入会报错或四舍五入(看版本和 sql_mode) 必须先查当前数据分布:
SELECT MIN(col), MAX(col), COUNT(*) FROM tbl WHERE col IS NOT NULL;
用 CHANGE COLUMN 还是 MODIFY COLUMN
CHANGE COLUMN和
MODIFY COLUMN都能改类型,但语义不同:
CHANGE必须写两次字段名(旧名 新名),哪怕不改名也得重复;
MODIFY只写一次,更简洁。两者在纯类型变更时行为一致,但
CHANGE允许同时改名+改类型,
MODIFY不允许改名。 只改类型、不改名 → 优先用
MODIFY COLUMN(少写、不易错) 要改名又改类型 → 必须用
CHANGE COLUMN old_name new_name new_type误写
CHANGE col col INT是合法的,但多打一个
col容易手滑漏掉,引发语法错误
修改 TEXT/BLOB 字段类型要加 ROW_FORMAT=DYNAMIC
MySQL 5.7+ 中,如果表用的是
COMPACT或
REDUNDANT行格式,直接对含
TEXT或
BLOB的字段执行
MODIFY,可能报错:
ERROR 1118 (42000): Row size too large。这是因为老行格式对单行总长有限制,而 TEXT 实际存储在行外,但元信息仍占空间。 先确认当前行格式:
SHOW TABLE STATUS LIKE 'tbl_name';看
Row_format列 若为
Compact,建议先改行格式:
ALTER TABLE tbl_name ROW_FORMAT=DYNAMIC;再执行字段修改,否则可能卡住或失败
DYNAMIC是 InnoDB 默认(8.0+),但老表迁移后未必自动更新
在线修改字段类型真的“在线”吗
MySQL 5.6+ 支持部分
ALTER TABLE操作的“在线”能力(即不锁表),但改字段类型是否真正不锁,要看具体操作和版本。例如
MODIFY COLUMN改
VARCHAR长度,在 5.7+ 中如果是扩大且字符集不变,通常可
ALGORITHM=INPLACE;但缩容、改类型(如
VARCHAR → TEXT)、或涉及全文索引时,大概率触发
COPY算法,锁表 + 全量复制。 加
ALGORITHM=INPLACE, LOCK=NONE强制指定,但 MySQL 会校验是否支持,不支持则报错 生产环境务必先在从库或测试库验证耗时与锁表现:
SHOW PROCESSLIST;观察状态 大表(千万级+)改类型前,用
pt-online-schema-change更稳妥 实际执行前,别跳过
SELECT ... LIMIT 5看真实数据样例,还有那个容易被忽略的
sql_mode设置——它会影响截断、零日期等行为的报错/警告策略。
