MyISAM转InnoDB必须停写,因ALTER TABLE非就地修改而是重建表并加读锁,写入持续将导致事务堆积、连接耗尽;mysqldump需按引擎差异选参,混用易丢数据;导入后须校验哈希、字符集、时区、自增ID及全文索引。

停写是硬前提,不暂停写入就动手,数据不一致是大概率事件,不是“可能”。
为什么MyISAM转InnoDB必须停写
ALTER TABLE table_name ENGINE = InnoDB 不是就地修改,而是新建 InnoDB 表、逐行复制、重建索引、最后原子替换。整个过程对原表加读锁——SELECT 可继续,但 INSERT/UPDATE/DELETE 全部阻塞。如果应用还在持续写入,事务会堆积、连接池耗尽、甚至触发超时中断。
- 别信“小表没事”:一张 50 万行、含
MEDIUMTEXT和多个联合索引的 MyISAM 表,重建可能耗时 10 分钟以上 - SHOW PROCESSLIST 必须确认无活跃写线程,不能只看监控图表
- 更稳妥的做法是通过代理层(如
ProxySQL)切走写流量,或临时关闭应用侧写逻辑
mysqldump 导出时怎么选参数才不丢数据
混合引擎库里,mysqldump 对 MyISAM 和 InnoDB 的一致性保障机制完全不同,混用默认参数极易漏数据。
- 只要库中存在任意一张
InnoDB表,必须加--single-transaction—— 它靠 MVCC 快照保证一致性,不锁表 - MyISAM 表无法被
--single-transaction保护,要么加--lock-all-tables(全库只读),要么提前停写后用--skip-lock-tables - 导出前务必执行
FLUSH TABLES WITH READ LOCK;+SHOW MASTER STATUS;记下 binlog 位置,用于后续比对 - 大字段(如
BLOB)容易因max_allowed_packet截断,导出前检查并调大该值
导入后哪些验证步骤不能跳过
行数一致 ≠ 数据正确。MyISAM 的 COUNT(*) 是元数据缓存,InnoDB 需实际扫描;字符集隐式转换、时区偏移、自增 ID 断层等问题不会报错,但会在对账时突然爆发。
- 用
CHECKSUM TABLE t1;对比源库和目标库关键表的哈希值,比SELECT COUNT(*)可靠得多 - 执行
SHOW CREATE TABLE t1;确认输出中ENGINE=InnoDB,且无残留DELAY_KEY_WRITE=1这类 MyISAM 特有语法 - 检查
SHOW TABLE STATUS LIKE 't1';中的Auto_increment值是否跳变,避免后续插入冲突 - 全文索引必须手动重建:
MyISAM的FULLTEXT在InnoDB下失效,且分词逻辑、停用词表、innodb_ft_min_token_size都需重新配置
大表迁移时容易卡死的三个资源瓶颈
当表超过 1GB 或百万级行数,ALTER TABLE ENGINE=InnoDB 很可能失败,不是语法问题,而是底层资源撑不住。
-
innodb_buffer_pool_size过小:复制过程频繁刷脏页,I/O 雪崩;建议设为物理内存的 50%–75% -
max_allowed_packet不够:某一行含巨大TEXT字段时,直接报错Packets larger than max_allowed_packet are not allowed - 磁盘剩余空间不足:重建过程需要等量临时空间,
ibdata1或独立表空间都会膨胀 - 此时别硬扛,改用
CREATE TABLE t1_new LIKE t1;+INSERT INTO t1_new SELECT * FROM t1;分批导入更可控
真正麻烦的不是 ALTER TABLE 执行失败,而是那些没显式声明字符集、没设时区、靠 MyISAM 行计数“蒙混过关”的老表——它们不会报错,但会在某个凌晨三点的订单对账里突然露馅。


















