alter table在生产环境易卡住,因默认会持有mdl写锁阻塞所有读写,尤其大表全表复制时长事务未提交导致“waiting for table metadata lock”堆积,引发业务雪崩。

ALTER TABLE 为什么在生产环境容易卡住?
因为 MySQL 的 ALTER TABLE 默认行为会锁表或阻塞读写,尤其在大表上——不是“慢”,而是“业务直接不可用”。你看到 Waiting for table metadata lock 状态时,说明已有长事务(比如没提交的 SELECT 或 UPDATE)占着 MDL 读锁,新 DDL 拿不到写锁,后续所有查询也都被堵住。
常见诱因包括:应用层未关闭事务、监控脚本执行了未加 LIMIT 的全表扫描、或 ORM 自动生成的长连接未显式 commit。只要有一个活跃事务没结束,ALTER TABLE 就可能无限等待。
- 先查有没有“钉子户”事务:
SELECT * FROM information_schema.PROCESSLIST WHERE COMMAND != 'Sleep' AND TIME > 60; - 确认阻塞源头:
SHOW PROCESSLIST;找出 State 为Waiting for table metadata lock的线程 ID,再用KILL [id]干掉它(谨慎操作) - 临时规避:用
SET SESSION lock_wait_timeout = 5;缩短等待上限,避免无限挂起
MySQL 5.7+ 添加字段怎么做到不锁表?
关键不是“能不能”,而是“怎么指定参数”。从 5.7 开始,InnoDB 支持 Online DDL,但默认行为仍可能退化为 COPY(尤其加 NOT NULL 且无 DEFAULT)。必须显式声明策略才能真正零阻塞。
例如给 users 表加一个可空字段:ALTER TABLE users ADD COLUMN avatar_url VARCHAR(255) NULL DEFAULT NULL COMMENT '头像地址', ALGORITHM=INPLACE, LOCK=NONE;
-
ALGORITHM=INPLACE强制走原地修改路径(不重建表) -
LOCK=NONE声明不加任何表级锁(注意:不是所有操作都支持,如改列类型通常不支持) - 加
NOT NULL字段时,必须带DEFAULT值,否则即使指定INPLACE也会退化为COPY并锁表 - MySQL 8.0 中
LOCK=NONE是多数 ADD COLUMN 场景的默认行为,但显式写出更稳妥
大表结构变更该不该用 pt-online-schema-change?
当表行数超过 100 万,或业务 SLA 要求“变更期间读写延迟 pt-online-schema-change。它不是银弹,但能绕过 MySQL 自身 DDL 的锁瓶颈。
原理是建影子表 → 增量同步数据 → 原子切换。代价是双倍磁盘空间、额外 binlog 流量、以及主从延迟风险(尤其在高写入场景下)。
- 必须提前检查:原表有主键(否则无法做增量同步)、binlog_format=ROW(STATEMENT 模式下触发器可能失效)
- 执行命令示例:
pt-online-schema-change --alter "ADD COLUMN tags JSON" D=mydb,t=orders --execute - 监控重点:检查
_old和_new临时表是否残留;观察pt_osc进程 CPU 和 IO 是否持续飙高 - 别在高峰期跑,也别让它跑过夜——加
--max-load="Threads_running=25"防止压垮数据库
UPDATE 数据前为什么必须开 sql_safe_updates?
这不是“防手抖”的功能,而是生产环境的强制护栏。一旦开启,任何没有 WHERE 条件、或 WHERE 条件未命中索引的 UPDATE/DELETE 都会被拒绝,直接报错 ERROR 1175。
它不阻止你改数据,只阻止你“裸奔式更新”。真正的安全来自两层:参数开关 + 人工校验。
- 会话级启用(推荐):
SET SESSION sql_safe_updates = 1;—— 开发/运维登录后第一件事 - 验证 WHERE 是否走索引:
EXPLAIN UPDATE users SET status=2 WHERE user_id=12345;看key列是否非 NULL - 批量更新必须带 LIMIT:
UPDATE logs SET processed=1 WHERE processed=0 LIMIT 1000;,并配合循环脚本分批执行 - 别依赖全局开启(
SET GLOBAL),权限不足或重启即失效,且可能影响其他服务
最易被忽略的一点:这个参数对存储过程内的 SQL 不生效——如果你的业务逻辑藏在 SP 里,得靠代码层加条件校验,不能只靠数据库开关兜底。











