必须用innodb:myisam不支持事务、无崩溃恢复、仅表级锁、count(*)语义错误、无外键,而innodb通过redo/undo log保障acid、行级锁、事务一致性count、自动崩溃恢复及外键约束。

事务支持:没有 START TRANSACTION 就别选 MyISAM
MyISAM 完全不支持事务,INSERT、UPDATE、DELETE 都是立即落盘的“裸写”。一旦执行中途崩溃(比如断电、kill -9),数据可能只写了一半,且无法回滚。InnoDB 则通过 redo log 和 undo log 保证 ACID:哪怕服务器突然宕机,重启后也能自动恢复到最近一次提交状态。
常见错误现象:
- 用 MyISAM 做订单表,用户支付成功但库存未扣减 → 数据不一致,无解
-
BEGIN; INSERT ...; UPDATE ...; COMMIT;在 MyISAM 中会被忽略,每条语句独立生效
实操建议:
- 只要业务涉及“要么全成、要么全败”,比如资金、库存、权限变更,必须用 InnoDB
- MyISAM 的
AUTO_INCREMENT不受事务保护:事务回滚后自增值不会回退,而 InnoDB 会(但注意:MySQL 8.0+ 对此做了优化,实际行为需验证)
锁机制:高并发写场景下,MyISAM 的 LOCK TABLES 是性能瓶颈
InnoDB 默认行级锁,UPDATE users SET status=1 WHERE id=123 只锁住这一行;其他线程仍可读/写其他用户记录。MyISAM 只有表级锁:UPDATE 或 INSERT 一上来就对整张表加排他锁,所有后续读写都排队等待。
容易踩的坑:
- 执行
UPDATE t SET x=1 WHERE name LIKE "%abc%"时,InnoDB 若无法使用索引定位具体行,也会升级为表锁 —— 这和引擎无关,是查询条件导致的,但 MyISAM 没有“升级”概念,它本来就是表锁 - MyISAM 写锁优先级高于读锁,即使已有 10 个
SELECT在排队,一个新来的INSERT会直接插队,造成读饥饿
实操建议:
- 日志类、归档类、报表源表(只追加、极少更新)可考虑 MyISAM,但前提是确认并发写压力为零
- 任何带用户交互的在线系统(如 CMS 后台、电商后台),哪怕只是后台管理操作,也应默认用 InnoDB
COUNT(*) 性能差异:不是“快慢问题”,而是“语义是否正确”
MyISAM 快是因为它在内存里缓存了精确行数,SELECT COUNT(*) FROM t 直接返回变量值;InnoDB 每次都要扫描索引(通常是主键或最小二级索引),结果取决于当前事务隔离级别下可见的行数。
关键点在于:
- MyISAM 的“快”只适用于无
WHERE条件的全表计数;一旦加条件,两者都得扫描 - InnoDB 的结果才是符合事务语义的:RR 隔离下,你看到的行数 = 当前事务能看到的行数,不是物理总行数
- 若真需要快速估算总数,可用
SHOW TABLE STATUS LIKE 't'查Rows字段(InnoDB 是估算值,误差可能达 40%)
别为了 COUNT(*) 改用 MyISAM —— 这相当于用数据一致性换毫秒级响应,代价远超收益。
外键与崩溃恢复:MyISAM 的“轻量”其实是功能缺失
InnoDB 支持外键约束,数据库层就能阻止非法关联数据插入;MyISAM 不支持,这类逻辑必须甩给应用层,极易遗漏或出错。更严重的是崩溃恢复:MyISAM 表损坏后,往往需手动运行 myisamchk 修复,且不能保证数据逻辑正确;InnoDB 启动时自动重放 redo log,99% 场景下无需人工干预。
容易被忽略的地方:
- MyISAM 的全文索引(
FULLTEXT)虽存在,但 InnoDB 自 MySQL 5.6 起已原生支持,且支持事务一致性 - MyISAM 表文件是独立的
.frm+.MYD+.MYI,方便直接拷贝,但这不是优势——InnoDB 的ibdata1或独立表空间(innodb_file_per_table=ON)同样可热备,且更安全 - MyISAM 的“读快”优势在现代 SSD + Buffer Pool 充足的环境下已大幅弱化,而它的锁和事务缺陷依然致命
现在 MySQL 8.0 默认引擎已是 InnoDB,连安装包都不再打包 MyISAM 插件。除非维护十年前的老系统,否则没必要再把它当备选项。











