面试知识库
基础

InnoDB与MyISAM对比#

一句话答案#

InnoDB 支持事务/行锁/外键/MVCC/崩溃恢复(默认引擎),MyISAM 只支持表锁,适合读密集场景。

核心要点

InnoDB 使用 B+ 树作为索引结构。

B+ 树的核心特点:

                    [30 | 60]               ← 非叶子节点(只存 key,不存数据)
                   /    |    \
           [10|20]   [40|50]   [70|80]
          /  |  \   /  |  \   /  |  \
        叶子节点(存 key + 完整数据行 / 主键值)
        [10]->[20]->[30]->[40]->[50]->[60]->[70]->[80]
              ↑ 叶子节点之间用双向链表相连
plaintext

关键特征:

  1. 非叶子节点只存 key,不存数据,路由用
  2. 叶子节点存 key + 数据(聚簇索引存完整行,二级索引存主键值)
  3. 叶子节点之间用双向链表连接,支持高效范围查询
  4. 所有数据都在叶子节点,查询路径长度固定(稳定的 O(log N))

两者 B+ 树叶子节点的本质差异(高频深挖):

维度MyISAM(非聚簇)InnoDB(聚簇)
主键索引叶子存什么行数据的物理地址(指向 .MYD 数据文件的偏移)完整行数据(数据就在主键 B+ 树叶子里)
二级索引叶子存什么行数据的物理地址(同主键索引)主键值(不是地址!)
主键 vs 二级索引结构对称——都是”索引值 → 物理地址”,没有谁是”主”不对称——主键聚簇、二级索引非聚簇
数据与索引文件分离:.MYI 存索引、.MYD 存数据一体:数据即索引(聚簇),存在 .ibd
查二级索引索引叶子直接拿到物理地址 → 一次定位拿到行索引叶子拿到主键 → 回表再查一次主键 B+ 树

为什么 InnoDB 二级索引叶子存”主键”而不是”物理地址”?

关键在于 InnoDB 是聚簇索引、且页可能分裂/合并。插入新行导致页满时会发生页分裂,已有行的物理位置会移动。如果二级索引存物理地址,每次页分裂就要回头更新所有二级索引里的地址,代价巨大。改存主键值——主键值不随物理位置变化而变化,行搬到哪都不影响二级索引,只是查询时多一次按主键回表的成本。

MyISAM 没有聚簇概念,数据行追加写入 .MYD、位置固定不变(删除留空洞也不移动其它行),所以叶子直接存物理地址既快又安全,主键和二级索引也就能用同一套”指向地址”的对称结构。

面试回答(2分钟版)

InnoDB 和 MyISAM 最核心的区别在于事务和锁。InnoDB 支持 ACID 事务、行级锁、MVCC 多版本并发控制和崩溃恢复,是 MySQL 5.5 之后的默认引擎;MyISAM 不支持事务,只有表级锁,并发写性能很差。索引结构上两者都用 B+ 树,但 InnoDB 的主键索引是聚簇索引,叶子节点存完整数据行,二级索引叶子存主键值需要回表;MyISAM 的索引和数据是分离的,叶子节点存的是数据文件的物理地址。MyISAM 有个优势是 count() 不带 WHERE 时可以直接返回存储的行数常量,但 InnoDB 因为 MVCC 的可见性需要逐行判断所以 count() 更慢。现在几乎所有业务场景都选 InnoDB,MyISAM 只在极少数只读且需要全文检索的历史场景才会碰到。

追问与易错

追问方向:

  • “现在为什么几乎不用 MyISAM?”→ 不支持事务和行锁,并发写性能极差;不支持崩溃恢复,宕机后数据易损坏;InnoDB 5.6+ 已支持全文索引,MyISAM 仅存优势基本消失
  • “MyISAM count(*) 为什么快?”→ MyISAM 内部维护了一个行数计数器,不带 WHERE 的 count(*) 直接返回该常量值,时间复杂度 O(1)
  • “InnoDB count(*) 怎么优化?”→ InnoDB 因 MVCC 需逐行判断可见性无法存计数器;优化方案:用最小的二级索引扫描减少 IO、维护 Redis/计数表缓存行数、或用 EXPLAIN 的 rows 做近似估算
  • “为什么 InnoDB 二级索引叶子存主键而不是行地址?”→ InnoDB 聚簇且页会分裂/合并,行的物理位置会移动;若二级索引存物理地址,每次页分裂都要更新所有二级索引的地址,代价极大。存主键值则行搬到哪都不影响二级索引,代价只是查询时多一次按主键回表。MyISAM 数据位置固定不变,所以叶子直接存物理地址,主键与二级索引结构对称

易错点:

  • ❌ MyISAM 没有任何优势——全文检索场景可用
  • ❌ InnoDB 不支持全文索引——5.6+ 已支持