需要先明确:pt-online-schema-change 对 MyISAM 表会直接拒绝——执行时立即报错 Cannot operate on MyISAM table `db`.`tbl`。这并非程序缺陷,而是设计上的根本限制:该工具依赖触发器(TRIGGER)实时同步数据行变更,而 MyISAM 仅支持语句级触发器,缺乏行级触发器支持,无法安全使用。简而言之,使用 pt-osc 前,必须先将 MyISAM 表手动转换为 InnoDB,然后才能进行在线 DDL 操作。

pt-online-schema-change 能否直接对 MyISAM 表进行操作?
不可以。pt-online-schema-change 默认会拒绝处理 MyISAM 表,并直接报错:Cannot operate on MyISAM table `db`.`tbl`。这并非程序缺陷,而是设计限制:该工具依赖触发器(TRIGGER)实时同步变更,而 MyISAM 不支持行级触发器(仅支持语句级,且 pt-osc 无法安全使用)。必须先手动将表转为 InnoDB,再用 pt-online-schema-change 进行后续 DDL 操作。
如何安全地将 MyISAM 表转换为 InnoDB?
切忌直接在线执行 ALTER TABLE tbl ENGINE=InnoDB——MyISAM 的 ALTER 操作会锁全表,业务高峰期可能锁定几分钟甚至更久。稳妥的做法是分两步进行:
- 首先使用
CREATE TABLE tbl_new LIKE tbl复制表结构(包括索引、注释等),然后执行ALTER TABLE tbl_new ENGINE=InnoDB修改引擎。 - 使用
INSERT INTO tbl_new SELECT * FROM tbl迁移数据;若数据量较大,可加WHERE按主键范围分批迁移,每批控制在 10000 行以内。 - 迁移完成后,用
RENAME TABLE tbl TO tbl_old, tbl_new TO tbl进行原子切换。注意 MyISAM 表名大小写敏感,库名和表名必须完全一致。 - 确认应用运行正常后,再执行
DROP TABLE tbl_old清理旧表。
关键之处在于:整个过程需要一次停写窗口。RENAME 本身是瞬时的,但 INSERT ... SELECT 期间新写入的数据会丢失,因此必须在业务低峰期暂停写入,或者使用 FLUSH TABLES WITH READ LOCK 短暂锁表以补全遗漏数据。
转成 InnoDB 后,用 pt-online-schema-change 做 DDL 的注意事项
此时表已是 InnoDB 引擎,pt-online-schema-change 终于可以正常工作,但仍需避开以下几个陷阱:
- 必须指定
--alter "ENGINE=InnoDB"(即使引擎已经是 InnoDB),否则工具可能跳过引擎检查,导致后续操作失败。 - 如果原 MyISAM 表包含全文索引(FULLTEXT),InnoDB 的全文索引行为存在差异(如最小词长、停用词规则不同),迁移后务必验证搜索逻辑是否受影响。
pt-osc默认会在从库上检查复制延迟。若原 MyISAM 表没有主键,切换后可能因INSERT DELAYED或自增冲突引发复制错误,请确保新表拥有显式主键。- 使用
SHOW PROCESSLIST监控pt-osc的操作线程,避免被max_statement_time或innodb_lock_wait_timeout参数打断。
为什么不能跳过 InnoDB 转换,直接使用其他工具?
目前市面上尚无成熟工具能够真正“在线”转换 MyISAM 引擎。mysqldump 导出导入必然需要停服;MySQL 8.0+ 的 ALTER TABLE ... ALGORITHM=INSTANT 仅支持列增删等小改动,不适用于引擎变更;Percona 自家的 pt-table-sync 也无法跨引擎同步。归根结底,这是 MyISAM 架构的硬伤:没有事务、没有行锁、没有 MVCC,所有号称“在线”的方案都只能通过外部双写或停写窗口来保证数据一致性。与其费心寻找绕过方法,不如将这次转换当作契机——推动业务彻底告别 MyISAM。
