MySQL 8.0+中真正支持LOCK=NONE的ALTER操作包括:ADD COLUMN(NULL字段)、VARCHAR扩容、RENAME/CHANGE COLUMN(类型不变)、增删二级索引、修改COMMENT或ROW_FORMAT;但改主键、设NOT NULL、缩小字段长度等仍需重建表并全表锁,必须显式指定ALGORITHM=INPLACE, LOCK=NONE并预发验证。

MySQL 8.0+ 添加 NULL 字段、增大 VARCHAR 长度、重命名列等操作,只要用 ALGORITHM=INPLACE, LOCK=NONE 显式指定,基本不锁表;但改主键、设 NOT NULL、缩小字段长度等仍会重建表并全表锁——别信“默认在线”,必须验证。
哪些 ALTER 操作真能无锁执行
不是所有 ALTER TABLE 都支持无锁。InnoDB 表在 MySQL 8.0 中真正能做到 LOCK=NONE 的常见操作有:
-
ADD COLUMN新增允许 NULL 的字段(如ADD COLUMN status TINYINT NULL) -
MODIFY COLUMN增大VARCHAR长度(如VARCHAR(100) → VARCHAR(255)),且不改变字符集或排序规则 -
CHANGE COLUMN或RENAME COLUMN字段名(类型和定义不变) -
ADD INDEX/DROP INDEX(非主键的二级索引) -
ALTER TABLE ... COMMENT = 'xxx'或调整ROW_FORMAT(满足引擎约束时)
关键点:必须显式写 ALGORITHM=INPLACE, LOCK=NONE,否则 MySQL 可能退化为默认策略(尤其在低版本或参数未调优时)。执行前先试跑不加 FORCE 的语句,看是否报错 "ALGORITHM=INPLACE is not supported" —— 报了就说明必须重建表。
为什么加 NOT NULL 字段会锁表
哪怕只是给一个空表加 NOT NULL,MySQL 也要扫描全表确认无 NULL 值。如果字段已有数据且含 NULL,ADD COLUMN col INT NOT NULL 会直接失败;若带默认值 ADD COLUMN col INT NOT NULL DEFAULT 0,8.0 虽支持 INSTANT 元数据变更,但前提是该列不参与聚簇索引且表行格式为 DYNAMIC 或 COMPRESSED。常见踩坑点:
- MySQL 5.7 不支持
ADD COLUMN ... NOT NULL DEFAULT的 INSTANT 操作,会触发 COPY - 即使 8.0,对
TEXT/BLOB列加NOT NULL仍需 INPLACE 且可能短暂LOCK=SHARED -
MODIFY COLUMN改类型 + 设NOT NULL(如INT → BIGINT NOT NULL)大概率触发重建,不要合并写
安全做法:先加允许 NULL 的字段,再用 UPDATE 补默认值,最后 ALTER TABLE ... MODIFY COLUMN ... NOT NULL —— 但第二次 MODIFY 仍要评估锁级别。
大表(千万级以上)别硬刚原生 DDL
即便操作理论上支持 INPLACE,超大表上执行仍可能因 I/O 压力、内存不足或长事务阻塞导致 ALTER 卡住,甚至拖垮从库复制延迟。此时应切换到成熟工具:
-
pt-online-schema-change:适合主库变更,靠触发器同步增量,但要求磁盘空间 ≥ 原表 2 倍,且禁止在目标表上手动删/改触发器 -
gh-ost:基于 binlog 解析做增量,不依赖触发器,主从均可操作,对主库负载更友好,但配置稍复杂 - 自建影子表迁移:需自行控制
INSERT ... SELECT分批大小、监控主从延迟、处理唯一键冲突,适合有强定制需求的场景
注意:pt-osc 默认会在原表加 WRITE LOCK 瞬间完成切换,但整个过程其余时间读写照常;而 gh-ost 切换是原子 Rename,无瞬时锁。二者都要求确保 binlog_format=ROW 且 binlog_row_image=FULL。
最容易被忽略的兼容性细节
同一句 ALTER 在不同环境表现可能天差地别:
- MySQL 5.6 完全不支持
ALGORITHM=INPLACE,所有ALTER默认COPY,锁表是必然的 - MySQL 5.7 对
ADD COLUMN支持 INPLACE,但MODIFY COLUMN改类型仍大概率 COPY(如TINYINT → INT) - 表的
ROW_FORMAT影响 INSTANT DDL:只有DYNAMIC和COMPRESSED支持新增字段 INSTANT;REDUNDANT或COMPACT会退化为 INPLACE -
innodb_strict_mode=ON是前提,否则某些隐式转换会绕过校验,导致后续出错
生产执行前,务必在同版本、同参数、同数据量级的预发环境实测,并用 SHOW PROCESSLIST 和 performance_schema.table_lock_waits_summary_by_table 观察真实锁行为——理论支持不等于线上可用。


















