myisam在生产写入场景下会丢数据,因其表级锁、无事务、无崩溃恢复机制,异常宕机后未刷盘变更丢失,auto_increment回退,主从易断链,且不支持外键和原子性on duplicate key update。

为什么 MyISAM 在生产写入场景下会丢数据
因为 MyISAM 的写操作是表级锁,且不支持事务。当一个 UPDATE 正在执行时,另一个 INSERT 或 DELETE 会被阻塞;更危险的是,如果此时 MySQL 进程异常退出(比如 kill -9、OOM killer 干掉 mysqld),MyISAM 只能靠 REPAIR TABLE 拼凑数据,但已提交但未刷盘的变更大概率丢失。
常见错误现象:Table is marked as crashed and should be repaired 频繁出现;主从同步延迟突增后,从库查不到刚插入的订单记录。
-
MyISAM的auto_increment是内存计数器,重启后可能回退或重复 - 没有崩溃恢复机制,binlog 和引擎层日志不一致,GTID 或基于 position 的主从容易断链
- 即使开了
sync_binlog=1,也无法保证 binlog 和引擎数据原子性提交
INSERT ... ON DUPLICATE KEY UPDATE 在 InnoDB 下才真正可靠
这个语法看似只是“存在就更新”,但底层依赖事务和行锁。只有 InnoDB 能在唯一索引冲突时精确锁定冲突行,避免并发插入导致的重复记录或覆盖错误。
使用场景:秒杀库存扣减、用户行为去重上报、配置项幂等写入。
-
MyISAM遇到冲突会直接报错Duplicate entry,无法平滑降级为更新 -
InnoDB的ON DUPLICATE KEY UPDATE是原子操作,不会出现“先查再插”引发的竞态 - 注意:必须有
UNIQUE或PRIMARY KEY索引,否则该语法退化为普通INSERT
主从复制中断后,InnoDB 能让数据追回来,MyISAM 很难
MySQL 主从依赖 binlog + 引擎层状态对齐。InnoDB 有 redo log 和 undo log,崩溃后可前滚/回滚到事务一致点;而 MyISAM 没有这些,crash 后只能靠文件系统级一致性(如 ext4 journal)兜底,不可控。
性能影响:InnoDB 的 redo log 是顺序写,吞吐高;MyISAM 的 .MYD 文件随机写,在 SSD 上也容易因缓存未刷导致不一致。
- 主库 crash 后重启,
InnoDB自动恢复未提交事务,binlog 位置与引擎状态严格对齐 -
MyISAM表可能处于半写状态(例如只写了部分行),mysqldump备份出来就是坏数据 - 从库执行
STOP SLAVE; START SLAVE;时,InnoDB可安全重放 relay log,MyISAM容易卡在Waiting for master to send event后数据错位
外键约束不是摆设,而是数据关系的硬边界
InnoDB 支持外键(FOREIGN KEY),MyISAM 完全不支持。这不是功能多寡问题,而是业务逻辑能否被数据库强制兜底的问题。
使用场景:订单表依赖用户表、评论表绑定文章 ID、权限表中 role_id 必须存在于角色表。
- 删用户前没检查订单,
MyISAM允许直接DELETE FROM user WHERE id=123,留下一堆脏订单 -
InnoDB默认启用FOREIGN_KEY_CHECKS=1,会拒绝破坏约束的操作,或按ON DELETE CASCADE自动清理 - 即使关掉外键检查(
SET FOREIGN_KEY_CHECKS=0),InnoDB表结构里仍保留定义,后续可审计、可重建约束
真正麻烦的不是选引擎,是上线后才发现某张 MyISAM 表正在被多个服务并发读写,而它的崩溃恢复行为没人真正验证过。











