mysql 5.7无法真正零停机重构大表,需用pt-online-schema-change实现毫秒级锁;algorithm=inplace不保证生效,受字段定义、长事务、引擎限制等影响;执行前须满足主键、无触发器、权限、外键处理四条件;关键参数应设--chunk-time=0.5、--max-load、--critical-load、--max-lag;收尾须清理残留触发器并校验表结构与数据一致性。

MySQL 5.7 中无法真正“零停机”重构大表,但可通过 pt-online-schema-change 实现毫秒级锁、业务无感的结构变更;原生 ALTER TABLE 在绝大多数场景下会退化为全表拷贝,必须避免直接使用。
为什么加了 ALGORITHM=INPLACE 还是被锁表?
MySQL 5.7 的 Online DDL 行为高度依赖具体操作和上下文,显式指定 ALGORITHM=INPLACE, LOCK=NONE 不代表一定生效:
- 字段定义触发隐式降级:比如
ADD COLUMN status TINYINT NOT NULL(无默认值)会强制回退到ALGORITHM=COPY,报错ERROR 1846 (HY000): ALGORITHM=INPLACE is not supported - 长事务阻塞元数据锁:哪怕只是
SELECT ... FOR UPDATE未提交,也会让 DDL 卡在Waiting for table metadata lock状态 - 引擎内部限制:如
MODIFY COLUMN缩小 VARCHAR 长度、DROP COLUMN、CHANGE COLUMN均需重建聚簇索引,不支持LOCK=NONE - 验证是否真在线:执行中查
information_schema.innodb_alter_table,若出现state = 'copy to tmp table',说明已退化为 COPY 模式
pt-online-schema-change 执行前必须满足的四个硬性条件
漏掉任一条件,工具会直接退出或导致数据不一致:
- 原表必须有主键或唯一非空索引,否则报错:
Cannot chunk table `db`.`t`: no primary key or unique not-null index - 原表不能存在任何触发器,否则提示:
Triggers exist on the table - 操作用户必须显式拥有
TRIGGER、REPLICATION SLAVE、PROCESS权限(仅SELECT/INSERT/UPDATE/DELETE不够) - 若该表被外键引用,必须指定
--alter-foreign-keys-method=auto或rebuild_constraints,否则RENAME阶段失败
生产环境关键参数怎么配才不拖垮线上库?
默认参数只适合测试环境,重点不是“快”,而是“可控”:
-
--chunk-time=0.5:控制每批拷贝耗时上限(秒),值越小对 IO/CPU 冲击越小;10GB 表建议设为0.3~0.5;别碰--chunk-size——它由--chunk-time动态反推 -
--max-load="Threads_running=25":当SHOW STATUS LIKE 'Threads_running'超过 25 时自动暂停,防止连接池雪崩 -
--critical-load="Threads_running=50":达到即中止,避免 DB 彻底卡死 -
--max-lag=1:从库延迟超 1 秒就暂停拷贝,防止复制中断;配合--check-interval=5(每 5 秒检查一次)使用
执行完之后最容易被忽略的两个收尾动作
很多线上事故不是出在执行过程,而是收尾没做干净:
- 异常中断后,原表上可能残留
pt_osc_db_t1_del/pt_osc_db_t1_ins/pt_osc_db_t1_upd触发器,必须手动清理:DROP TRIGGER IF EXISTS pt_osc_db_t1_del(把db和t1替换成实际值) - 替换完成后,工具虽自动
RENAME并删旧表,但必须人工核对:SHOW CREATE TABLE t1确认字段/索引/字符集是否正确,再用pt-table-checksum校验数据一致性——仅靠COUNT(*)不可靠,触发器同步期间可能有极少量延迟











