不能用ALTER TABLE t ENGINE=InnoDB实现真正不停机转换——它在MySQL 8.0及以下版本中强制走COPY算法,全程持MDL写锁,阻塞所有写入及部分读取,磁盘需双倍空间,主从延迟剧增;唯一可靠方案是pt-online-schema-change,依赖主键或唯一索引、innodb_file_per_table=ON、主从延迟为0且须提前删除FULLTEXT索引。

不能用 ALTER TABLE t ENGINE=InnoDB 实现真正不停机转换——它在任何 MySQL 8.0 及以下版本中,对 MyISAM 表强制走 COPY 算法,全程持 MDL 写锁,业务写入必然中断。
为什么 ALTER TABLE ... ENGINE=InnoDB 在生产环境等于停机
这不是参数没加对、也不是运气差,而是 MySQL 内核级限制:MyISAM → InnoDB 的引擎切换不支持 ALGORITHM=INPLACE,无论你写不写 LOCK=NONE,MySQL 都会自动降级为 LOCK=EXCLUSIVE。
-
SHOW PROCESSLIST中状态长期卡在copy to tmp table—— 这不是“准备中”,是真正在全量搬数据 - 所有
INSERT/UPDATE/DELETE被拒绝;SELECT在REPEATABLE-READ下也可能因 MVCC 版本链阻塞 - 磁盘空间需 ≥ 原
.MYD+.MYI总大小 × 2.2(含 redo log 增长、临时排序文件) - 主库执行时 binlog 积压,从库回放卡在锁释放后,
Seconds_Behind_Master可能跳到数小时
pt-online-schema-change 是唯一可落地的“准在线”方案
它靠影子表 + 触发器双写维持一致性,业务无感,但必须满足四个硬性前提,缺一不可:
- 表必须有主键或唯一非空索引(否则报错
This table has no primary key or unique index) -
innodb_file_per_table = ON(MySQL 5.6+ 默认开启,用SHOW VARIABLES LIKE 'innodb_file_per_table'确认) - 主从延迟为 0(
Seconds_Behind_Master = 0,否则影子表数据滞后) - 先手动
DROP INDEX ft_idx ON t(MyISAM 的FULLTEXT索引 pt-osc 不支持迁移)
典型命令:
pt-online-schema-change \ --alter "ENGINE=InnoDB" \ D=your_db,t=big_table \ --execute \ --chunk-size=300 \ --max-lag=1 \ --check-interval=5 \ --critical-load="Threads_running=25"
--chunk-size 要按单行平均大小调小:宽表建议 100–300,避免单事务过大触发 innodb_log_file_size 溢出。
转换后必须人工验证,工具不会替你担责
pt-online-schema-change 完成后只是完成了表替换,但不保证语义等价。容易被忽略的关键点:
- 旧
.MYD/.MYI文件不会自动删除,确认新表数据一致前严禁rm - 外键约束在 MyISAM 中被忽略,InnoDB 会严格校验——若存在脏数据,首次
INSERT就报ERROR 1452 - 只比
COUNT(*)不够:需比对SUM(amount)、MIN(created_at)等关键聚合值 - 全文查询行为可能变化:
innodb_ft_min_token_size默认值不同,停用词、分词器逻辑不一致,需同步调整并重建索引
配置不调优,转完等于白转
InnoDB 和 MyISAM 内存模型完全不同,引擎改完立刻要调参:
-
innodb_buffer_pool_size设为物理内存的 50%–75%,别留着默认 128M -
key_buffer_size从几百 MB 降到 32M 左右(MyISAM 专用缓存) - 非金融场景可设
innodb_flush_log_at_trx_commit = 2,降低刷盘压力 - 检查
default_storage_engine = InnoDB是否写进my.cnf并重启生效(仅影响新建表)
最常被跳过的一步:迁移后没关 FOREIGN_KEY_CHECKS 就直接开业务,结果第一条插入就失败,错误提示模糊,排查成本远高于提前清理脏数据。


















