聚簇索引、二级索引、回表与覆盖索引分别是什么?

结论先行:InnoDB 中聚簇索引的叶子节点直接存整行数据,二级索引的叶子只存索引列 + 主键;通过二级索引查非索引列要回聚簇索引再取一次,称为回表;若查询列都在二级索引里则无需回表,称为覆盖索引。

一、两类索引的本质区别

对比项聚簇索引(主键索引)二级索引(辅助索引)
叶子内容完整行记录索引列值 + 主键值
每表数量只能一个可以多个
数据组织行按主键物理顺序存放逻辑有序,需按主键回表
常见举例PRIMARY KEY(id)KEY idx_name(name)

二、回表是怎么发生的

SELECT * FROM user WHERE name = 'zhang';
1) 走二级索引 idx_name,找到主键 id = 18
2) 拿主键 18 再去聚簇索引 B+Tree 查整行   ← 这一步就是回表
  • 回表本质是两次 B+Tree 查找,索引区分度低或命中行多时代价会被放大。
  • 优化方向:让二级索引覆盖目标列,或用索引下推减少回表行数。

三、覆盖索引:把查询列装进索引

-- idx(name, age):二级索引里同时有 name 与 age
SELECT name, age FROM user WHERE name = 'zhang';  -- 无需回表

-- 只给 age 条件,违反最左前缀,通常走不到 idx(name, age)
SELECT name, age FROM user WHERE age > 20;
  • 覆盖索引 = 查询所需列全部存在于同一个二级索引,Extra 显示 Using index。
  • 代价:索引里冗余的列越多,写入与空间开销越大,只覆盖高频查询列即可。

四、索引下推(ICP)与联合索引的配合

  • 联合索引按最左前缀生效(见第 28 章),覆盖列尽量从左往右设计。
  • MySQL 5.6+ 支持索引下推:在二级索引内先过滤部分条件,减少回表行数。

常见追问与记忆点

  • 追问:InnoDB 为什么必须有聚簇索引?没有主键就用首个非空唯一键,再没有则隐藏生成 ROWID。
  • 追问:回表一定慢吗?不一定,命中行少且都在内存页时代价很小,量大才成问题。
  • 记忆点:聚簇 = 叶子存行,二级 = 叶子存主键;回表 = 拿主键再查一次,覆盖 = 列全在索引里。
笔记加载中…