innodb是绝大多数业务的默认且合理选择,因其支持事务、外键和崩溃恢复,能保证原子性操作(如订单创建+库存扣减)全成功或全失败;myisam无回滚机制、仅表级锁、无自动恢复能力,仅适用于纯读场景。

InnoDB 是绝大多数业务的默认且合理选择,除非你明确知道为什么不用它。
需要事务、外键或崩溃恢复时必须用 InnoDB
只要业务涉及“原子性操作”,比如订单创建+库存扣减+日志记录这三步必须全成功或全失败,就必须用 InnoDB。MyISAM 没有 ROLLBACK,一旦中间出错,数据就处于不一致状态。
- 常见错误现象:
UPDATE执行一半失败,表里只更新了部分行,应用层无法感知或回退 - 数据库重启后
MyISAM表可能报crashed,需手动REPAIR TABLE -
InnoDB的redo log和undo log是崩溃后自动恢复的基础设施,MyISAM没有等价机制
高并发写入场景下 MyISAM 的表级锁是硬伤
MyISAM 所有写操作(INSERT/UPDATE/DELETE)都会对整张表加排他锁,后续任何读写都排队等待。哪怕只是更新一行,其他线程查另一行也得等。
-
InnoDB默认行级锁,UPDATE users SET status=1 WHERE id=123只锁住这一行 - 但注意:
InnoDB的行锁只在WHERE条件命中索引时生效;若WHERE name LIKE "%abc%"无法走索引,也会退化为全表扫描+意向锁 - 监控上
Table_locks_waited持续上升,往往就是MyISAM表在高并发写入时被卡住的信号
COUNT(*) 性能差异本质是语义不同,不是快慢问题
MyISAM 快,是因为它把精确行数缓存在内存里,SELECT COUNT(*) FROM t 直接返回变量值;但这个值在事务隔离下不准确——比如你刚 INSERT 一条但没 COMMIT,别人查不到,而 MyISAM 的缓存值已经变了。
-
InnoDB每次都按当前事务可见性去扫索引(通常是主键),结果严格符合隔离级别定义,但代价是可能变慢 - 真要高频查总数?加个冗余字段(如
total_count),在事务里同步更新 - 用近似值够用?查
information_schema.TABLES里的TABLE_ROWS(误差可能达 40%) - 避免在大表上直接跑
SELECT COUNT(*)——无论引擎,都是全表扫描
仅读多写少且无事务需求时,MyISAM 才值得考虑
比如静态配置表、只读日志归档表(如 sys_log_202501),MyISAM 的 COUNT(*) 不扫表、索引更轻量、内存占用更低——但这优势正被现代硬件和 InnoDB 优化持续削弱。
- 即使只读,也要确认:未来会不会加关联约束?是否可能迁移到分布式或 CDC 场景?
InnoDB提前预留能力更稳妥 -
MyISAM的AUTO_INCREMENT不受事务保护——回滚后自增 ID 仍会递进,容易引发业务逻辑错乱 - 服务器异常断电后,
MyISAM表损坏概率远高于InnoDB,且修复过程不可控
InnoDB 的复杂点不在语法或配置,而在理解它如何把一致性、并发、恢复打包成一个默认可用的契约;而 MyISAM 看似简单,却把所有风险都推给了使用者自己判断。











