加个字段,全站报错
产品要在订单表加一个 remark 字段,老王看表才 4000 万行,随手一条 ALTER TABLE——三秒后接口全线超时报警。这一课学费贵,这篇把大表 DDL 的坑位和正规姿势一次讲透。
先懂堵车:MDL 元数据锁
DDL 动表结构,必须拿到这张表的 MDL 写锁;查询和 DML 拿 MDL 读锁,读写互斥。规则只有两条,但组合起来很要命:
- MDL 写锁申请要排队等所有读锁释放;
- 写锁等待期间,新来的读锁也排在它后面——后面所有查询全部堵死。
于是一个未提交的长事务(哪怕只是 SELECT)持着读锁不放,你的 ALTER 排队,全表的业务查询跟着一起排队——雪崩。排查方法第 15 篇的 metadata_locks 就是为此准备的。做 DDL 前先确认没有长事务,是第一军规。
Online DDL:数据库自带的温和方案
5.6 起 InnoDB 支持在线 DDL,DDL 期间读写大多不被阻塞(短暂的锁只在开始和结束的瞬间)。每种操作的支持度不同,用 ALGORITHM 显式声明并让数据库拒绝不支持的写法:
# INSTANT:只改元数据,秒级完成(8.0.12+ 加列的主力)
ALTER TABLE orders ADD COLUMN remark VARCHAR(255) DEFAULT NULL, ALGORITHM=INSTANT;
# INPLACE:引擎内重建,不复制整表到服务层,期间可读写(耗时但不断流)
ALTER TABLE orders ADD INDEX idx_amount (amount), ALGORITHM=INPLACE, LOCK=NONE;等级:INSTANT(秒改元数据)> INPLACE(引擎内原地重建)> COPY(建影子表全量复制,锁写)。8.0 的加列默认 INSTANT,这是 8.0 值得升级的实在理由之一;但修改列类型、加全文索引等仍要走 INPLACE 甚至 COPY。INPLACE 重建大表依然要数小时、占双倍空间、产生大量 redo——不断流不等于没成本,主从延迟(第 12 篇)会被 DDL 结束时的大事务补课拉爆。
gh-ost:可控割接的外科手术
更大的表(亿级)、或对限速有要求时,用 gh-ost 这类工具,原理三步:
- 建影子表:按目标结构建 orders_ghost,空表;
- 拷数据 + 追增量:分批把原表数据拷进影子表,同时订阅 binlog 把期间的增删改持续回放到影子表(顺序、限速都可控);
- 原子割接:数据追平后 RENAME TABLE 原子换名,业务无感。
对比 Online DDL,gh-ost 付出的是双倍存储与更长的总耗时,换来的是可暂停、可限速、可观测、随时中止——生产环境大表变更的安心丸。pt-online-schema-change 同理(用触发器追增量,gh-ost 用 binlog,后者对业务更无侵入)。
大表 DDL 作业清单
- 先查长事务:
information_schema.innodb_trx清场; - 低峰期执行,明确 ALGORITHM,让不支持的语句直接报错而不是偷偷 COPY;
- 亿级表或需限速:gh-ost,变更前演练与预估时长;
- 主从架构下关注从库回放延迟,必要时逐台执行;
- 能不加字段就不加:扩展表、JSON 字段(低频访问的附属信息)是缓兵之计,但别当万能药。
表结构动得了,数据量继续涨怎么办?分库分表的临界点判断和拆分姿势,下一篇讲。
咖啡凉了,记得趁热喝。
评论 (0)