一句话总结
InnoDB 支持事务、行锁、外键、崩溃恢复(redo log),是 MySQL 5.5+ 默认引擎,适合 OLTP 场景。MyISAM 不支持事务、只有表锁、不支持外键,但查询速度快,适合读多写少的 OLAP 场景。核心区别:InnoDB 是"聚簇索引"(主键索引叶子存数据),MyISAM 是"非聚簇索引"(索引叶子存数据地址)。
初级理解
核心区别对比表
| 对比维度 | InnoDB | MyISAM |
|---|---|---|
| 事务 | ✅ 支持(ACID) | ❌ 不支持 |
| 锁粒度 | 行锁 + 间隙锁 | 表锁 |
| 外键 | ✅ 支持 | ❌ 不支持 |
| 崩溃恢复 | ✅ redo log 保证 | ❌ 崩溃后需修复表 |
| MVCC | ✅ 支持 | ❌ 不支持 |
| 索引结构 | 聚簇索引(B+树叶子存数据) | 非聚簇索引(B+树叶子存地址) |
| 全文索引 | MySQL 5.6+ 支持 | ✅ 原生支持 |
| count(*) | 需要扫描 | 有变量存储,O(1) |
| 存储文件 | .ibd(数据和索引) | .MYD(数据)+ .MYI(索引) |
| 适用场景 | OLTP(高并发读写) | OLAP(读多写少) |
中级深入
索引结构的本质区别
InnoDB 聚簇索引:主键索引的 B+树叶子节点存储完整行数据,二级索引叶子节点存储主键值(需要回表)。
MyISAM 非聚簇索引:主键索引和二级索引的 B+树叶子节点都存储数据行的物理地址,没有回表概念。
为什么 MyISAM 查询比 InnoDB 快?
1. 不需要回表:索引直接指向数据地址
2. 没有事务开销:不需要维护 undo log、redo log、MVCC 版本链
3. count(*) 有缓存:表中有变量记录总行数
4. 表锁开销小:虽然并发差,但单次加锁开销比行锁小
InnoDB 为什么必须有主键?
InnoDB 使用聚簇索引组织数据,必须有主键来构建 B+树。如果建表时没有指定主键,InnoDB 会:
1. 找第一个 NOT NULL UNIQUE 索引作为聚簇索引
2. 如果都没有,自动生成一个隐藏的 6 字节 row_id 作为聚簇索引
高级拓展
Memory 引擎(HEAP)
数据全部存在内存中,重启后数据丢失。默认使用哈希索引,等值查询极快,但不支持范围查询。适合做临时表或缓存表。
如何选择存储引擎?
| 场景 | 推荐引擎 | 原因 |
|---|---|---|
| 电商订单系统 | InnoDB | 需要事务保证数据一致性 |
| 日志/审计表 | MyISAM 或 Archive | 只追加不修改,查询少 |
| 计数/统计表 | MyISAM | count(*) 快,无事务需求 |
| Session 存储 | Memory | 数据可丢失,追求速度 |
| 全文搜索 | InnoDB(5.6+)或 Elasticsearch | InnoDB 已支持全文索引 |
实战场景
场景:MyISAM 表迁移到 InnoDB
面试模拟
面试官:InnoDB 和 MyISAM 有什么区别?
你:核心区别:1)InnoDB 支持事务和行锁,MyISAM 不支持事务只有表锁;2)InnoDB 是聚簇索引(主键叶子存数据),MyISAM 是非聚簇索引(叶子存地址);3)InnoDB 支持崩溃恢复(redo log),MyISAM 崩溃后需要修复表;4)InnoDB 支持外键和 MVCC,MyISAM 不支持。生产环境默认用 InnoDB。
面试官:为什么 InnoDB 推荐用自增主键?
你:InnoDB 使用聚簇索引,数据按主键顺序存储。自增主键每次插入都在最后,不会引起页分裂和页合并,插入效率最高。如果用 UUID 等随机主键,插入位置随机,会导致频繁的页分裂,降低写入性能,还会造成索引碎片。