pt-online-schema-change并非真正无锁,而是将锁拆分为小段以保障业务读写;其核心原理是创建影子表、加触发器同步变更、分块拷贝数据后原子替换,需严格配置参数并执行预检。

pt-online-schema-change 不是“无锁”,而是把锁拆成小段——它能让你在 ALTER TABLE 时业务照常读写,但前提是配置对、环境稳、操作慎。直接跑 --execute 很容易翻车。
为什么不能直接 ALTER TABLE 大表?
MySQL 5.7 对多数 DDL 仍需全表拷贝:改字段类型、删列、加唯一索引、调整字符集等,都会触发 ALGORITHM=COPY。10GB 表可能卡住几十分钟,期间所有 INSERT/UPDATE/DELETE 排队等待 Waiting for table metadata lock,SELECT 在 RR 隔离级别下也可能被阻塞。
即使 MySQL 8.0.12+ 支持 ALGORITHM=INSTANT 加列,也仅限新增列且不带默认值或 NOT NULL 约束;其他变更仍要走拷贝流程。
- 查当前是否真支持 INPLACE:MySQL 官方 DDL 支持矩阵,别凭经验猜
- 长事务没提交?
ALTER会一直等它释放 MDL,哪怕只是个没COMMIT的SELECT - 主从延迟高、从库 IO 压力大时,
ALTER可能加剧延迟,甚至触发复制中断
pt-online-schema-change 启动前必须做的三件事
跳过预检就 --execute,等于把数据库交到运气手里。
- 先用
SHOW PROCESSLIST和pt-query-digest看写入峰值和慢查询分布,避开订单高峰、日终结算时段 - 强制加
--dry-run:只建影子表、验权限、试触发器,不拷数据也不改名;失败了立刻停,不伤原表 - 设资源保护阈值:
--max-load="Threads_running=25"(超载暂停)、--critical-load="Threads_running=50"(超限退出)、--max-lag=1(从库延迟超 1 秒停同步)
关键参数怎么配才不出事?
pt-online-schema-change 默认参数适合测试环境,线上大表必须调。
-
--chunk-size=5000:默认 1000 行太保守,大表可提到 5000,但别超过 10000 —— 单次锁行太久会拖慢主表写入 -
--chunk-time=0.5:控制每批拷贝耗时上限(秒),值越小对线上影响越轻,总耗时变长,建议 0.3–0.5 -
--check-interval=5:每 5 秒检查一次max-lag和max-load,太频繁增加监控压力,太长错过风险窗口 -
--alter里只写单条语句,比如"MODIFY COLUMN phone VARCHAR(20) NOT NULL",不能带分号,也不能逗号连写多条
哪些操作它兜不住,千万别硬上
工具再强也有边界,强行改可能丢数据、主键失效、触发器残留。
-
DROP PRIMARY KEY:影子表没了主键,触发器同步逻辑崩掉,直接报错退出 -
MODIFY COLUMN缩容(如VARCHAR(255) → VARCHAR(50)):工具不校验截断,已有超长数据会被静默截断 - 表上有
ON DELETE CASCADE或自定义触发器:pt-osc默认拒绝执行,得先清理 - JSON 字段加虚拟列并建索引:MySQL 5.7+ 支持,但
pt-osc3.5.x 版本有 bug,建议升到 3.7.0+
执行完 rename 成功、旧表删了、触发器没了,不代表数据对——务必手动比对行数、抽样查关键字段、验证应用逻辑是否正常。很多“结构变了、数据丢了”的 case,都是省了这一步。











