最安全的大表加字段方式是显式指定 DEFAULT 值,如 ALTER TABLE users ADD COLUMN status TINYINT DEFAULT 1;避免隐式默认、锁表风险及主从延迟,优先用 ALGORITHM=INSTANT 或 pt-online-schema-change。

ALTER TABLE ADD COLUMN 时直接指定 DEFAULT 值最安全
大表加字段不设默认值,后续 INSERT 会报错;设了但没写 DEFAULT 关键字,MySQL 5.7+ 会静默用隐式默认(比如 0 或空字符串),和预期不符。
- 必须显式写
DEFAULT:例如ALTER TABLE users ADD COLUMN status TINYINT DEFAULT 1 - 如果字段允许 NULL,又没写
DEFAULT,新字段对老数据是NULL;写了DEFAULT NULL才明确可控 - MySQL 8.0.13+ 支持
ADD COLUMN ... DEFAULT 'xxx' STORED,但普通场景不用加STORED,它只影响生成列 - 注意:
DEFAULT CURRENT_TIMESTAMP只对TIMESTAMP和DATETIME有效,其他类型会报错Invalid default value
给已有大表加带默认值的字段,为什么还会锁表?
MySQL 5.6+ 对 ADD COLUMN 做了优化,但如果表有全文索引、外键、或用了 MyISAM 引擎,仍会全程锁表;即使 InnoDB,加字段时若没走“instant DDL”,也会触发拷表。
- 判断是否走 instant:执行后查
SHOW PROFILE或看INFORMATION_SCHEMA.INNODB_TABLES中ALGORITHM字段是否为INSTANT - 触发拷表的常见原因:
ADD COLUMN同时加NOT NULL且无默认值、字段类型是TEXT/BLOB、表使用ROW_FORMAT=COMPRESSED - 安全做法:先加字段带
DEFAULT+ 允许NULL,确认成功后再用ALTER TABLE ... MODIFY COLUMN调整约束(这步可能锁表,但数据量小)
修改已有字段的默认值,用 ALTER COLUMN MODIFY 还是 CHANGE COLUMN?
两者都能改默认值,但语义和风险不同:MODIFY COLUMN 只改定义,CHANGE COLUMN 连字段名一起改;误写字段名会导致列被重命名甚至丢数据。
- 只改默认值,统一用
ALTER TABLE t1 ALTER COLUMN c1 SET DEFAULT 'new'(MySQL 8.0.13+)或ALTER TABLE t1 MODIFY COLUMN c1 VARCHAR(50) DEFAULT 'new' - MySQL 5.7 不支持
ALTER COLUMN ... SET DEFAULT,必须用MODIFY重申整个字段定义,漏写原类型/约束会清空它们(比如忘了写NOT NULL,字段就变可空了) - 执行前务必备份:改默认值本身不改存量数据,但
MODIFY若类型变更(如VARCHAR(10)→VARCHAR(20))在旧版本可能触发拷表
线上大表加字段,怎么避免主从延迟暴增?
DDL 在主库执行期间,从库回放可能卡住,尤其当主库负载高、从库 IO 或 SQL 线程慢时;更麻烦的是,DDL 语句本身会被记录为单条 QUERY_EVENT,无法并行回放。
- 避开业务高峰,用
pt-online-schema-change(需提前测试兼容性)或 MySQL 8.0 的ALGORITHM=INSTANT(仅限加字段/删字段等极简操作) - 检查从库状态:
SHOW SLAVE STATUS\G中Seconds_Behind_Master和SQL_Delay,延迟 > 60 秒时暂停 DDL - 如果必须用原生命令,加
ALGORITHM=INPLACE, LOCK=NONE(不是所有操作都支持),并监控performance_schema.table_lock_waits_summary_by_table - 别依赖
SET SESSION lock_wait_timeout = 1来“防锁”,它只影响 DML,对 DDL 无效
真正难的不是语法,是判断「这个 ALTER 到底走不走拷表」——光看文档不行,得在同规格从库上先 EXPLAIN FORMAT=JSON 或开 innodb_monitor_output 看实际执行路径。










