MySQL主从复制中MyISAM因无事务机制和crash-safe保障,易致静默数据不一致;InnoDB同步可靠性取决于innodb_flush_log_at_trx_commit与sync_binlog严格设为1。

MySQL 主从复制中,InnoDB 和 MyISAM 的行为差异会直接导致同步异常或数据不一致——这不是配置问题,而是引擎底层机制决定的。
主从复制下 MyISAM 表可能“不同步”但不报错
MyISAM 没有事务日志(redo log、undo log),写操作直接落盘;主库执行 INSERT 后,binlog 记录的是语句本身(STATEMENT 格式)或行变更(ROW 格式),但 MyISAM 不保证这些变更在崩溃时可重放。如果主库写入中途崩溃,binlog 可能已刷盘而数据未写完,从库回放后出现“多一行”或“少一行”。更隐蔽的是:MyISAM 的 COUNT(*) 依赖内存计数器,主从重启后该值可能不一致,但复制不会报错。
- STATEMENT 模式下,
INSERT ... SELECT或含UUID()、NOW()的语句在从库执行结果可能不同 - ROW 格式虽能规避部分问题,但 MyISAM 无 crash-safe 机制,从库应用 event 失败时可能跳过而不中断复制
- 主库执行
REPAIR TABLE或OPTIMIZE TABLE后,binlog 不记录物理文件变化,从库表结构与数据实际状态脱节
InnoDB 的同步可靠性依赖事务边界和 binlog 刷盘策略
InnoDB 同步是否可靠,关键不在引擎本身,而在 innodb_flush_log_at_trx_commit 和 sync_binlog 的组合。默认值 innodb_flush_log_at_trx_commit = 1 + sync_binlog = 1 才能保证“提交即持久”,否则主库崩溃可能导致已提交事务丢失,从库永远追不上。
- 若设为
innodb_flush_log_at_trx_commit = 2,事务提交只写 OS cache,断电即丢;此时即使sync_binlog = 1,binlog 已落盘,但 InnoDB 数据没落盘,从库回放后主从数据不一致 - 使用 GTID 时,MyISAM 表的 DDL(如
ALTER TABLE)可能被当作自动提交事务,干扰 GTID 顺序;InnoDB 表的 DDL 在 8.0+ 默认加锁并生成单个 GTID,行为更可控 - 从库开启
read_only = 1对 MyISAM 无效:MyISAM 表仍可通过INSERT DELAYED或非事务方式绕过
混合引擎表在集群中会放大同步风险
一张表不能跨引擎,但一个库可以同时存在 InnoDB 和 MyISAM 表。问题在于:DDL 操作(如 CREATE TABLE ... ENGINE=MyISAM)和 DML 混合时,binlog 中事件顺序无法保证原子性。例如主库执行:
START TRANSACTION;
INSERT INTO innodb_orders VALUES (1, 'paid');
INSERT INTO myisam_logs VALUES ('order_1_created');
COMMIT;
从库回放时,两个 INSERT 分属不同引擎,无法回滚其中一条——若第二条失败,第一条已生效,主从状态分裂。
- mysqldump 导出时默认不带
--set-gtid-purged=OFF,含 MyISAM 表的 dump 可能导致 GTID 集不匹配,从库启动失败 - Percona XtraBackup 支持 InnoDB 热备,但对 MyISAM 只能冷备(需全局读锁),备份窗口内主库写入无法同步到从库
- ProxySQL 或 MaxScale 做读写分离时,若路由规则未按引擎区分,MyISAM 的写操作可能被误发到只读从库,报错但不中断连接
真正麻烦的不是“选哪个引擎”,而是当业务已在线上混用两者时,SHOW SLAVE STATUS 看不到延迟,pt-table-checksum 却发现校验和不一致——这种静默错误最难定位。


















