不能直接用alter table t engine=innodb批量执行——mysql 8.0仍强制copy算法,全程mdl写锁阻塞读写、主从延迟飙升、磁盘翻倍;必须转的表包括:有持续写入或外键依赖的表、数据量>1gb且高可用要求的表、需事务/行锁/崩溃恢复的表;可暂缓的有只读小表(≤100mb)和含fulltext索引且版本不兼容的表。

不能直接用 ALTER TABLE t ENGINE=InnoDB 批量执行——MySQL 8.0 及升级后版本仍强制走 COPY 算法,全程持有 MDL 写锁,业务写入阻塞、主从延迟飙升、磁盘空间翻倍是大概率事件。
哪些 MyISAM 表真该转,哪些可以不动
盲目转换既浪费资源,又可能引入全文索引不兼容、隐式 ROW_ID、事务行为异常等问题。优先处理三类表:
- 有持续写入(
table_rows明显变动)或被外键引用的表 - 数据量 >1GB 且业务要求高可用(如订单、用户行为日志)
- 需要事务、行级锁或崩溃后可恢复能力的表
以下表可暂缓迁移:
- 只读小表(≤100MB),比如
sys_config、dict_status - 含
FULLTEXT索引但 MySQL 版本 - 无主键/唯一非空索引的表(
pt-online-schema-change会直接报错This table has no primary key or unique index)
查存量命令: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');
大表必须用 pt-online-schema-change,别信 LOCK=NONE
MySQL 8.0 中 ALTER TABLE t ENGINE=InnoDB 即使加 LOCK=NONE,也会自动降级为 LOCK=EXCLUSIVE。真正能落地的线上无锁方案只有 pt-online-schema-change,它通过影子表 + 触发器双写实现平滑过渡。
前提硬性要求:
- 目标表必须有显式主键或唯一非空索引
-
innodb_file_per_table = ON(5.6+ 默认开启,建议确认) binlog_format = ROW- 禁用
LOAD DATA INFILE或REPLACE INTO等绕过触发器的操作
关键参数示例:pt-online-schema-change --alter "ENGINE=InnoDB" D=your_db,t=big_table --execute --chunk-size=1000 --max-lag=1 --check-interval=5
注意:pt-osc 迁移后不会自动删除旧的 .MYD 和 .MYI 文件,必须人工验证 CHECKSUM TABLE 一致后再清理。
转换后必须调参和验证,否则性能可能更差
InnoDB 行为与 MyISAM 差异极大,引擎改完不调参等于白转:
-
innodb_buffer_pool_size必须设为物理内存的 50%–75%,否则大量磁盘读 -
key_buffer_size从几百 MB 降到 32M 左右(MyISAM 不再使用) -
innodb_flush_log_at_trx_commit非金融场景可设为2(崩溃最多丢 1 秒数据)
必须验证两件事:
-
COUNT(*)结果是否与原表一致(在相同隔离级别下执行) - 业务 SQL 是否仍能正常执行,尤其涉及
MATCH AGAINST的全文查询(InnoDB 分词器、停用词、innodb_ft_min_token_size默认值不同)
特别注意:若原表含 AUTO_INCREMENT 列但未建索引,ALTER TABLE 会报 ERROR 1075;InnoDB 要求该列必须是索引的一部分(通常是主键或联合索引中的一员)。











