普通索引(二级索引,非主键索引)在 InnoDB 中的执行流程与主键索引有根本区别,因为它不直接存储整行数据,而是仅存储索引列 + 主键值。理解其执行路径,特别是“回表”和“覆盖索引”,是优化查询性能的关键。
🔍 一、普通索引的本质回顾
- 普通索引(或唯一索引)也是一棵独立的B+ 树,按索引列排序。
- 内部节点:存储索引列值 + 子页指针。
- 叶子节点:存储索引列值 + 对应主键值,不含其他列数据。
- 叶子节点间也通过双向链表连接,支持顺序扫描。
- 因此,通过普通索引找到数据后,通常还需要到主键索引(聚簇索引)中去获取完整行,这个过程称为回表。
🎯 二、普通索引的等值查询流程(非覆盖)
以 SQL 为例:
SELECT*FROMusersWHEREname='Alice';假设name列建有普通索引idx_name(name),主键是id,且查询需要所有列(非覆盖)。
步骤详解:
1. 服务层选择索引
- 优化器评估后认为使用
idx_name比全表扫描成本更低,决定走普通索引。 - 执行器通过 Handler API 发起索引查找。
2. 在普通索引 B+ 树中定位'Alice'
- 从
idx_name的根页开始,通过垂直导航和页内二分查找,找到叶子节点中键值为'Alice'的记录。 - 假设叶子节点中
'Alice'对应的主键id=10。
3. 获取主键值
- 引擎从该叶子记录中提取主键值
10,返回给执行器(内部实际上直接进行下一步,不会暂停)。
4. 回表 —— 用主键值访问聚簇索引
- 引擎拿着
id=10,到聚簇索引(主键索引)中再次进行 B+ 树搜索,定位到对应的叶子页。 - 在聚簇索引叶子页中找到
id=10的整行数据(包含所有列),并返回。
5. 权限验证与返回客户端
- 执行器对行数据进行最终权限检查,通过后返回给客户端。
流程图: