InnoDB 引擎中,聚簇索引的叶子节点直接存储完整行数据,非聚簇索引的叶子节点存储索引列值加主键值。主键查询无需回表,非主键查询通常需要通过主键回表获取完整数据。
先说结论:聚簇索引决定数据物理存储顺序,一张表只能有一个;非聚簇索引独立存储,支持多个。
- 适合:主键查询、范围查询场景
- 重点看:叶子节点是存数据行还是主键值
- 别忽略:非聚簇索引查询完整数据需要回表
快速处理思路
通过查看表结构定义确认聚簇索引,通过执行计划确认查询是否命中索引。
SHOW CREATE TABLE table_name;
检查 PRIMARY KEY 定义,InnoDB 默认主键即为聚簇索引。
为什么会这样
存储引擎设计决定了 B+ 树叶子节点的内容差异。聚簇索引将数据行与索引结构融合,非聚簇索引将数据与索引分开存储。
聚簇索引的 B+ 树叶子节点包含主键值及所有字段数据。非聚簇索引的 B+ 树叶子节点包含索引键值及对应的主键值,不包含完整行数据。
分步处理
第一步:确认聚簇索引。检查表是否有主键,若无主键且无唯一非空索引,InnoDB 会隐式生成 row_id 作为聚簇索引。
第二步:确认非聚簇索引。查看除主键外的其他索引,这些均为非聚簇索引,叶子节点存储主键值。
第三步:评估查询路径。若查询字段包含在非聚簇索引中,可避免回表;若需查询非索引列,则需回表操作。
怎么验证是否生效
使用 EXPLAIN 命令查看查询执行计划,关注 type 和 Extra 字段。
EXPLAIN SELECT * FROM table_name WHERE id = 1;
若 type 为 const 或 ref 且 Extra 显示 Using index,说明命中索引。若需回表,Extra 可能显示 Using where。
常见坑
- 隐式主键:未定义主键时,InnoDB 生成隐藏 row_id,影响性能且不可见。
- 回表成本:非聚簇索引查询非索引列时,需二次查找聚簇索引,增加 IO 开销。
- 主键更新:聚簇索引数据按主键顺序存储,频繁更新主键会导致页分裂和数据移动。
常见问题
一张表可以有多个聚簇索引吗
不可以。聚簇索引决定数据物理存储顺序,一张表只能有一种物理顺序,因此只能有一个聚簇索引。
非聚簇索引查询一定慢吗
不一定。若查询字段完全覆盖在索引中(覆盖索引),无需回表,性能接近聚簇索引查询。
没有主键的表聚簇索引是什么
InnoDB 会选择第一个唯一非空索引,若都没有,会隐式创建一个 6 字节的 row_id 作为聚簇索引。
参考来源
- 浅谈聚簇索引和非聚簇索引的区别
- MySQL 的 InnoDB 引擎中聚簇索引和非聚簇索引
- 详解 MySQL InnoDB 引擎中的聚簇索引和非聚簇索的区别
- MySQL InnoDB 引擎中的聚簇索引和非聚簇索引有什么区别?_mysql 中 innodb 非聚簇索引相同值数据默认排序-CSDN 博客
- InnoDB 聚集索引和非聚集索引、覆盖索引、回表、索引下推简述