会,且是全表锁;MySQL添加自增主键必须重建表,导致长时间阻塞读写,大表可能停机数十分钟。

ALTER TABLE加自增主键会锁表吗
会,而且是全表锁(在非只读事务下),尤其对大表可能阻塞业务数分钟甚至更久。MySQL 5.6+ 的 ALGORITHM=INPLACE 仅支持部分 DDL,但添加 PRIMARY KEY 或 AUTO_INCREMENT 字段并设为主键时,**必须重建表**——这意味着复制数据、重建索引、重写 .ibd 文件。即使你用的是 MySQL 8.0,只要新字段要成为主键,就绕不开这个过程。
常见错误现象:ALTER TABLE t ADD COLUMN id BIGINT AUTO_INCREMENT PRIMARY KEY FIRST; 在执行中,其他会话对 t 的 SELECT/INSERT/UPDATE 都会被挂起,SHOW PROCESSLIST 里能看到状态为 Waiting for table metadata lock 或 copy to tmp table。
- 如果表有 1TB 数据且磁盘 I/O 较慢,操作可能持续几十分钟
- binlog 会记录整张表的重建事件,从库回放压力陡增
- 若中途失败(如磁盘满、OOM),已写入的临时文件不会自动清理,需手动干预
不锁表的替代方案:先加字段,再分批补值,最后设主键
核心思路是避开“一步到位”的重建,把高风险操作拆解为低影响步骤。适用于无法接受长时间停机的生产环境。
实操分三步:
-
第一步:添加无默认值、非空、非主键的字段
ALTER TABLE t ADD COLUMN id BIGINT NOT NULL AFTER some_col;—— 这个 DDL 在 MySQL 5.6+ 中通常是INPLACE(仅修改表定义,不触碰行数据),毫秒级完成 -
第二步:分批次更新 id 值(用自增逻辑模拟)
先查出当前最大 id:SELECT COALESCE(MAX(id), 0) FROM t LIMIT 1;,记为@base;再用类似下面的语句分批更新(每批 10 万行):UPDATE t SET id = @base := @base + 1 WHERE id = 0 ORDER BY some_col LIMIT 100000;
注意:必须有确定排序依据(比如时间戳或已有唯一索引列),否则跨批次可能重复或跳号 -
第三步:添加唯一索引并设为主键
ALTER TABLE t ADD UNIQUE INDEX uk_id (id);→ 成功后再ALTER TABLE t DROP PRIMARY KEY, ADD PRIMARY KEY (id);。第二步确保了id全局唯一且非空,所以这一步才安全
为什么不能直接用 ROW_NUMBER() 或 UUID 替代自增
MySQL 8.0+ 支持 ROW_NUMBER(),但它不能用于 DDL 的 DEFAULT 表达式,也无法在 ADD COLUMN ... DEFAULT 中调用;而 UUID() 是字符串、不可排序、索引效率差,且不符合“自增”语义(后续插入仍需手动维护)。
更关键的是:如果你后续要用该字段做分库分表键、作为外键被其他表引用,或依赖其单调递增特性做时间序推断,UUID 和随机生成的数字都会导致严重问题。
-
DEFAULT UUID()会导致每行插入都触发函数计算,性能开销明显 -
ROW_NUMBER() OVER(ORDER BY ...)只能在 SELECT 中用,不能固化到字段上 - 试图用触发器在 INSERT 时赋值?大表上触发器本身就会成为性能瓶颈,且无法批量导入(LOAD DATA 会绕过触发器)
真正要检查的三个前置条件
动手前漏掉任一条件,都可能导致操作失败或数据异常:
-
确认表引擎是 InnoDB:MyISAM 不支持在线 DDL 的很多优化,且自增行为不同;用
SHOW CREATE TABLE t;查看ENGINE=InnoDB - 检查磁盘剩余空间是否 ≥ 表大小 × 2:重建表需要额外空间存临时文件,分批更新方案也需预留 undo log 和 buffer pool 增长空间
-
验证是否有未提交的长事务:用
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(NOW()) - TIME_TO_SEC(TRX_STARTED) > 60;找出运行超 1 分钟的事务,它们会阻塞 DDL 的元数据锁获取
最常被忽略的是第三点——一个没被发现的长事务会让 ALTER TABLE 卡在“Waiting for table metadata lock”长达数小时,而 DBA 以为是磁盘慢或 CPU 满,实际只是某条忘记 COMMIT 的调试 SQL 在那儿挂着。


















