pt-online-schema-change 不直接锁表,但通过触发器间接导致写入延迟,读操作不受影响;其原理是影子表+触发器同步,主表始终在线,前提是mysql支持触发器、binlog开启且无长事务阻塞mdl。

pt-online-schema-change 执行时表到底锁不锁
它本身不直接锁表,但会通过触发器间接造成写入延迟,读操作完全不受影响。本质是用影子表+触发器同步数据,主表始终在线——前提是你的 MySQL 版本支持触发器、binlog 开启、且没有长事务阻塞 ALTER TABLE 的元数据锁(MDL)。
常见错误现象:Waiting for table metadata lock 卡住,不是 pt-online-schema-change 在锁表,而是它启动前检测到有活跃事务正拿着 MDL,必须等它们结束才能开始。
- 执行前务必检查
SHOW PROCESSLIST,杀掉长时间运行的SELECT或未提交事务 - 避免在业务高峰跑,哪怕不锁表,触发器也会吃 CPU 和 IO,写入 QPS 高时可能堆积
- 5.7+ 推荐加
--no-check-plan,否则执行计划预估可能误判导致中止
哪些 ALTER 操作能用 pt-online-schema-change 安全执行
支持绝大多数 DDL:加减字段、改类型(需兼容)、加索引、删索引、改默认值。不支持的包括:RENAME TABLE、OPTIMIZE TABLE、修改 PRIMARY KEY(除非新主键包含旧主键所有列)、以及任何需要重建全文索引的操作。
使用场景:线上订单表加 status_updated_at 字段,或给大表补一个查询用的联合索引。
- 改字段类型要小心,比如
VARCHAR(255)→VARCHAR(500)可以,但INT→BIGINT在某些版本会触发全量拷贝而非原地变更 - 加唯一索引必须确保数据无重复,工具不会帮你校验,失败后回滚代价高
- MySQL 8.0.12+ 原生支持
ALGORITHM=INSTANT的操作(如加字段),此时用原生命令更快更稳,不必上 pt 工具
为什么 --execute 必须显式加,而且不能漏掉
pt-online-schema-change 默认只做 dry-run:建影子表、同步数据、对比结构,但不切换。你看到 “Successfully altered `db`.`tbl`” 实际只是日志打印,表还是原来的。
容易踩的坑:运维脚本里忘了写 --execute,或者复制命令时漏了这半截,结果白跑了两小时,业务毫无感知,也毫无变化。
- 安全起见,先跑一遍不带
--execute的命令,确认输出末尾是Operation stopped at ...而非报错 - 切换瞬间会有短暂(毫秒级)的
RENAME TABLE,依赖该表的连接可能抛Table doesn't exist,应用层要有重试逻辑 - 别用
--dry-run测试性能,它跳过拷贝和触发器,压测没意义
出问题怎么快速回退
工具会在开始前自动备份原表名到 _tbl_old(可配前缀),只要没手动删掉,回退就是一条 RENAME TABLE。
但注意:如果执行中途被 kill 或断电,影子表和触发器可能残留,下次再跑会报错。
- 先查残留:
SHOW TRIGGERS LIKE 'tbl%'、SHOW TABLES LIKE '\_tbl\_new' - 手动清理:
DROP TRIGGER IF EXISTS tbl_after_insert、DROP TABLE IF EXISTS \_tbl\_new - 回退命令:
RENAME TABLE tbl TO \_tbl\_bad, \_tbl\_old TO tbl—— 注意顺序,反了就丢数据
真正麻烦的不是回退动作,而是你改完发现新字段类型不对、索引没生效、或者应用代码读到了空值——这些得靠上线前在影子表上验证 SQL,而不是依赖工具本身。











