一、聚簇索引(Clustered Index)
核心特点:索引和数据放在一起,叶子节点直接存整行数据。
InnoDB 里,主键索引就是聚簇索引。
-
B+ 树的叶子节点 存放的是完整的一行数据
-
找到索引,就等于找到了整行,不需要再回表
类比 :像一本字典,正文本身就是按拼音排序的,你按拼音翻到那一页,字和解释都在那一页。
如果没有主键怎么办?
InnoDB 会这样选聚簇索引:
-
有主键 → 用主键
-
没主键 → 选第一个唯一非空索引
-
都没有 → 自动生成一个隐藏的 row_id 做聚簇索引
所以每张 InnoDB 表一定有且只有一个聚簇索引。
二、非聚簇索引(二级索引 / 辅助索引)
核心特点:索引和数据分开,叶子节点存的是主键值,不是整行数据。
除了聚簇索引,你建的其他索引都是非聚簇索引 (也叫二级索引)。
-
B+ 树的叶子节点 存放的是索引列的值 + 主键值
-
通过二级索引找到的只是主键,不是完整数据
类比 :像书的目录,目录只告诉你"第 100 页",具体内容还得去正文(聚簇索引)里翻。
举例
表 users:
| id(主键) | name | age |
|---|---|---|
| 1 | 张三 | 20 |
| 2 | 李四 | 25 |
-
聚簇索引 (主键 id):叶子节点存
(1, 张三, 20)、(2, 李四, 25) -
非聚簇索引 (在 name 上建索引):叶子节点存
(张三, 1)、(李四, 2),只存 name 和主键 id
三、回表(Back to Table)
回表 = 通过二级索引找到主键后,再拿主键去聚簇索引里查一次完整数据。
什么时候会回表
sql
SELECT * FROM users WHERE name = '张三';
执行过程:
-
走
name的二级索引,找到name = 张三对应的主键 id = 1 -
拿
id = 1去聚簇索引 里查,拿到整行(1, 张三, 20) -
返回结果
第 2 步就是回表。
怎么判断有没有回表
用 EXPLAIN 看 Extra:
-
有
Using index→ 用了覆盖索引,不回表 -
只有
Using where,没有Using index→ 可能回表
四、怎么避免回表:覆盖索引
覆盖索引 :查询需要的列,全都在索引里,不用回表。
sql
-- 建联合索引
CREATE INDEX idx_name_age ON users(name, age);
-- 查询列都在索引里
SELECT name, age FROM users WHERE name = '张三';
-
索引
(name, age)的叶子节点存(张三, 20, 1) -
查询要的
name、age都在索引里 -
直接返回,不用回表
EXPLAIN 里会显示 Extra = Using index。
注意 :如果写成 SELECT *,要的列超出了索引范围,就还是要回表。