面试知识库
极高 进阶

聚簇索引与非聚簇索引#

一句话答案#

聚簇索引(主键)叶子存完整行数据,非聚簇索引(二级索引)叶子存主键值,查完整数据需回表。

核心要点

InnoDB: 主键索引=聚簇索引 / 二级索引=非聚簇索引(叶子存主键ID→需回表)

回表: 通过二级索引找到主键 → 再通过主键索引查完整行

覆盖索引: 索引包含查询所需全部字段 → 无需回表

面试回答(2分钟版)

InnoDB 中聚簇索引就是主键索引,B+ 树叶子节点直接存储完整行数据,按主键顺序物理排列。每张表有且只有一个聚簇索引,如果没有显式主键,InnoDB 会选择唯一非空索引,都没有则隐式创建 6 字节的 DB_ROW_ID,所以 InnoDB 必须有主键。非聚簇索引也叫二级索引,叶子节点存的是对应的主键值而非完整行数据。通过二级索引查询时如果需要的字段不全在索引中,就要先拿到主键值再去聚簇索引查完整行,这个过程就是回表,相当于查了两次 B+ 树,IO 开销较大。实际优化中通过覆盖索引避免回表,即建联合索引让查询所需字段都包含在索引中,二级索引上就能拿到全部数据。另外建议用自增整型做主键,因为聚簇索引按主键排列,自增插入是顺序写入不会导致页分裂,性能更好。

追问与易错

追问方向:

  • “为什么建议自增 ID 做主键?”→ 聚簇索引按主键物理排列,自增 ID 顺序插入追加在 B+ 树尾部,不会触发页分裂;整型主键占字节少,二级索引叶子存的主键值也更小,索引更紧凑
  • “非聚簇索引一定要回表吗?”→ 不一定,如果查询字段全部包含在索引中(覆盖索引),直接从二级索引返回数据无需回表;EXPLAIN Extra 显示 Using index 即为覆盖索引
  • “InnoDB 必须有主键吗?”→ 是的,如果没有显式定义主键,InnoDB 会选择第一个非空唯一索引作为聚簇索引;都没有则自动生成一个隐藏的 6 字节 DB_ROW_ID 作为主键

易错点:

  • ❌ 非聚簇索引直接存行数据——存的是主键值
  • ❌ MyISAM 也有聚簇索引——MyISAM 都是非聚簇