ALTER TABLE ... SET DEFAULT 不修改已有行数据,仅影响后续INSERT未指定该列时的行为;旧数据保持原状,即使为NULL也不会被自动更新为新默认值。

ALTER TABLE ... SET DEFAULT 不会修改已有行数据
给已有字段加默认值,只是影响后续 INSERT 时没显式提供该列值的行为。旧数据完全不动——哪怕字段当前是 NULL 或空字符串,也不会被自动更新成新默认值。
常见错误现象:SELECT 结果里大量旧记录仍是 NULL,误以为默认值“生效了”,其实它只管未来插入。
- 使用场景:表已上线、有历史数据,但新业务逻辑要求新增字段必须有兜底值
-
ALTER TABLE t ADD COLUMN status TINYINT DEFAULT 1→ 新增字段带默认值,旧行该列全为NULL(除非用NOT NULL+DEFAULT组合,见下条) -
ALTER TABLE t ALTER COLUMN status SET DEFAULT 2→ 修改默认值,对旧数据无任何影响
加 NOT NULL 才可能触发旧数据检查
真正容易出问题的是在已有数据的表上,给字段加 NOT NULL 约束的同时设默认值。MySQL 会尝试用默认值填充所有 NULL 行——但前提是这些行确实为 NULL,且默认值类型兼容。
常见错误现象:ERROR 1138: Invalid use of NULL value 或 ERROR 1265: Data truncated for column,尤其当字段原为 TEXT、JSON 或有长度限制时。
- 执行
ALTER TABLE t MODIFY COLUMN name VARCHAR(50) NOT NULL DEFAULT 'unknown'→ MySQL 会把所有name IS NULL的旧行设为'unknown' - 但如果旧数据里有超长字符串或非法 JSON,而新默认值又无法覆盖所有情况,就会报错中断
- 安全做法:先
UPDATE t SET name = 'unknown' WHERE name IS NULL,再加约束
DEFAULT 属性在 INSERT 中的实际行为
默认值只在 INSERT 语句中“省略该列”或显式写 DEFAULT 时起作用。它不参与 UPDATE,也不影响 SELECT 查询逻辑。
常见错误现象:写 INSERT INTO t (id) VALUES (1),以为 status 会自动填默认值,结果发现插入失败——其实是字段定义了 NOT NULL 但没给默认值,或者引擎不支持(如 MyISAM 对 TEXT 字段不支持默认值)。
- 正确触发默认值的写法:
INSERT INTO t (id) VALUES (1)(字段本身有DEFAULT且非NOT NULL限制),或INSERT INTO t (id, status) VALUES (1, DEFAULT) - InnoDB 支持几乎所有类型的默认值(包括表达式如
CURRENT_TIMESTAMP),MyISAM 仅支持常量 - 注意:MySQL 8.0.13+ 才支持
JSON、GEOMETRY类型的字面量默认值
线上加默认值要留意隐式锁和复制延迟
在大表上执行 ALTER TABLE ... ALTER COLUMN ... SET DEFAULT 通常很快(元数据操作),但若同时加 NOT NULL,就可能触发全表扫描甚至重建,导致锁表时间不可控。
常见错误现象:主库 ALTER 执行秒级完成,但从库复制卡住几小时——因为 DDL 被记录为 statement-based 格式,从库需重放整张表变更。
- 确认是否真需要改旧数据:多数时候只需加默认值,别顺手加
NOT NULL - 用
pt-online-schema-change或 MySQL 8.0+ 的ALGORITHM=INSTANT(仅限部分操作)规避锁表 - 检查
binlog_format:设为ROW可减少从库重放风险
默认值不是数据迁移工具,它只守门,不擦屁股。真要批量修正旧数据,得靠 UPDATE 配合条件判断,别指望 DEFAULT 属性越界干活。











