不能直接用alter table t engine=innodb做平滑迁移,因其在mysql 8.0中强制copy算法、锁表、耗双倍磁盘空间且拖垮主从;真正需迁移的是有写入、数据量>1gb或需事务/行级锁的表;平滑方案唯一可靠的是pt-online-schema-change,依赖主键或唯一索引,通过影子表+触发器实现无锁转换。

不能直接用 ALTER TABLE t ENGINE=InnoDB 做“平滑”迁移——它在 MySQL 8.0 中仍是全表 COPY,锁表、耗空间、拖主从,生产环境等同于主动停服。
哪些 MyISAM 表真该动?先筛再动
不是所有 MyISAM 表都值得迁移。盲目转 InnoDB 可能引入全文索引行为变化、隐式 ROW_ID、内存争抢等问题。优先处理三类表:
- 有写入(
table_rows频繁变动)或被外键引用的表 - 数据量 >1GB 且业务要求高可用(如订单、用户行为日志)
- 需要事务、行级锁或崩溃后可恢复能力的表
只读小表(≤100MB)、纯配置/字典表、带 FULLTEXT 但没升级到 MySQL 5.6+ 的旧表,可暂缓——强行转反而触发重建开销和分词逻辑不一致。
查存量命令:SELECT table_schema, table_name, table_rows, data_length FROM information_schema.tables WHERE engine = 'MyISAM' AND table_schema NOT IN ('mysql', 'information_schema', 'performance_schema');
为什么 ALTER TABLE ... ENGINE=InnoDB 不是平滑操作?
MySQL 8.0 对 MyISAM → InnoDB 的引擎变更仍强制走 COPY 算法,不支持 ALGORITHM=INPLACE。过程本质是:
- 创建新 InnoDB 表结构
- 逐行拷贝数据 + 重建索引
- 重命名交换,删旧文件
这期间会:
- 持有 MDL 写锁,阻塞所有
INSERT/UPDATE/DELETE;部分隔离级别下SELECT也可能卡住 - 磁盘空间需 ≥ 原
.MYD+.MYI总大小 ×2(含 redo/undo/临时文件) -
SHOW PROCESSLIST显示状态为copy to tmp table,不是“准备中”,是真的在搬数据 - 即使加
LOCK=NONE,MySQL 也会自动降级为LOCK=EXCLUSIVE
真正能落地的平滑方案:用 pt-online-schema-change
这是目前生产环境唯一可靠的无锁迁移路径。它通过影子表 + 触发器双写同步变更,业务几乎无感,但前提是表必须有主键或唯一非空索引。
典型命令:pt-online-schema-change --alter "ENGINE=InnoDB" D=your_db,t=big_table --execute
关键注意事项:
- 执行前确认主键存在:
SHOW KEYS FROM your_table WHERE Non_unique = 0 AND Seq_in_index = 1; -
--chunk-size控制每次迁移行数(默认 1000),大表建议调小(如 500)降低单次压力 -
--max-lag防止从库延迟过大时自动暂停,避免复制雪崩 - 迁移完成后,
.MYD/.MYI文件不会自动删除,需人工核对数据一致后再清理
迁移后必须立刻检查的几件事
只看 SHOW TABLE STATUS LIKE 't' 显示 Engine=InnoDB 远不够。容易忽略但致命的问题包括:
- FULLTEXT 索引需手动重建:
ALTER TABLE t DROP INDEX ft_idx; ALTER TABLE t ADD FULLTEXT(title, content);—— 因innodb_ft_min_token_size(默认 3)≠ft_min_word_len(MyISAM 默认 4),搜索结果可能变 - 外键字段必须已有索引,否则
ALTER TABLE会静默失败;用information_schema.KEY_COLUMN_USAGE核对外键是否生效 -
INSERT DELAYED已废弃,InnoDB 完全不支持,得改批量INSERT或应用层队列 - 高频
COUNT(*)查询变慢是正常现象(InnoDB 不维护精确行数),别急着归因引擎,先看执行计划是否走了索引扫描
最麻烦的是隐性依赖:比如原 MyISAM 表被当计数器高频更新,换成 InnoDB 后没加事务控制,反而引发死锁——这种得结合 SHOW ENGINE INNODB STATUS 和业务日志交叉排查。











