MySQL 索引

qinyelin
发布于 2026-08-26 / 0 阅读
0
0

MySQL 索引

MySQL 索引

面试频率:★★★★★
工作频率:★★★★★


⚡ 30 秒速记

一句话:

索引是一种帮助 MySQL 快速查找数据的数据结构。

InnoDB 索引主要使用:

B+ Tree

核心:

MySQL索引
   ↓
B+树
   ↓
树比较矮
   ↓
减少磁盘 / 数据页访问
   ↓
提高查询效率

主键索引:

主键B+树
   ↓
叶子节点
   ↓
完整行数据

叫:

聚簇索引

二级索引:

普通索引B+树
   ↓
找到主键ID
   ↓
主键B+树
   ↓
找到完整数据

这个过程叫:

回表

一、什么是索引?

可以把索引理解成:

数据库的目录。

例如一本书:

没有目录

↓

从第一页开始找

↓

很慢

有目录:

找到目录

↓

找到页码

↓

直接去对应位置

数据库也是一样。

例如:

SELECT *
FROM user
WHERE id = 9527;

如果没有索引:

可能需要:

从第一条开始

↓

一条一条找

↓

全表扫描

如果:

1000万条数据

效率会很低。

有索引:

通过索引

↓

快速定位数据

所以:

索引的主要作用就是提高数据查询效率。


二、索引是不是越多越好?

不是。

索引可以提高:

SELECT

查询速度。

但是也有成本。

例如:

INSERT INTO user ...

UPDATE user ...

DELETE FROM user ...

修改数据的时候:

数据库可能还需要维护:

索引

所以:

索引越多

↓

INSERT / UPDATE / DELETE

↓

维护索引成本越高

而且索引本身:

需要占用存储空间

所以:

索引不是越多越好,要根据实际查询场景建立。


三、InnoDB 索引主要使用什么数据结构? ⭐⭐⭐⭐⭐

答案:

B+ Tree

例如可以粗略理解:

                  [30 | 60]
                 /    |     \
                /     |      \
         [10 20]   [40 50]   [70 80 90]
             ↓         ↓          ↓
           叶子       叶子        叶子

注意:

真正的 B+ Tree 比这个复杂。

目前先理解:

一个节点

可以存很多索引项

所以:

树的高度比较低

四、为什么不用普通二叉树?

普通二叉树:

        50
       /  \
     30    70
    /        \
   20        80

一个节点通常只有:

两个子节点

如果数据非常多:

树可能比较高

数据库查找:

根节点
 ↓
下一层
 ↓
下一层
 ↓
下一层
 ↓
...

树越高:

需要访问的数据页可能越多

效率就可能越低。


五、为什么 B+ Tree 适合数据库? ⭐⭐⭐⭐⭐

B+ Tree:

一个节点可以保存:

多个索引项

例如:

          [10 | 20 | 30 | 40 | 50]
        /      |       |       \
       ↓       ↓       ↓        ↓

这样:

一个节点

↓

可以管理更多子节点

所以:

同样1000万条数据

↓

B+树可以保持比较低的高度

数据库查询时:

访问较少的数据页

↓

找到目标数据

所以效率比较高。


六、B+ Tree 第一个特点:树比较矮 ⭐⭐⭐⭐⭐

数据库索引非常关注:

数据页访问次数

假设 B+ Tree:

根节点
  ↓
中间节点
  ↓
叶子节点

可能几层:

就可以管理:

大量数据

所以:

数据很多

≠

需要一条一条扫描

而是:

通过B+树

↓

快速定位叶子节点

七、B+ Tree 第二个特点:非叶子节点主要用于导航

例如:

                [30 | 60]
               /    |     \

这里:

30

60

主要作用:

判断下一步往哪里找

例如查:

id = 50

看到:

30 < 50 < 60

于是:

往对应的子节点继续查找

所以:

非叶子节点主要用于索引导航。


八、B+ Tree 第三个特点:数据集中在叶子节点 ⭐⭐⭐⭐⭐

最终查询:

根节点
   ↓
中间节点
   ↓
叶子节点

最终:

在叶子节点找到目标记录或记录定位信息

所以:

非叶子节点
↓

主要导航


叶子节点
↓

真正保存对应的数据 / 索引记录

九、B+ Tree 第四个特点:叶子节点有序连接 ⭐⭐⭐⭐⭐

例如:

[1 5 10]
    ↔
[15 20 25]
    ↔
[30 35 40]
    ↔
[45 50 55]

叶子节点:

按照索引顺序排列

+

彼此连接

这个特点特别适合:

范围查询

十、为什么 B+ Tree 适合范围查询?

例如:

SELECT *
FROM user
WHERE id BETWEEN 20 AND 40;

首先:

通过B+树

↓

找到20

然后:

20
 ↓
25
 ↓
30
 ↓
35
 ↓
40

沿着:

叶子节点

继续扫描即可。

所以:

B+ Tree 不仅适合等值查询,也非常适合范围查询。


十一、什么是聚簇索引? ⭐⭐⭐⭐⭐

InnoDB 中:

主键索引通常就是聚簇索引。

它最大的特点:

主键索引B+树

↓

叶子节点保存完整行数据

例如:

主键索引:

              [10 | 20]
             /    |     \
            ↓     ↓      ↓


叶子节点:

id=1
name=张三
age=20


id=2
name=李四
age=25


id=3
name=王五
age=30

也就是说:

主键索引叶子节点

↓

就是完整记录

十二、主键查询为什么很快?

例如:

SELECT *
FROM user
WHERE id = 10;

如果:

id是主键

流程:

主键B+树
   ↓
根据id查找
   ↓
找到叶子节点
   ↓
直接获得完整行数据

所以:

主键查询

↓

不需要再去另一个索引找完整数据

十三、什么是二级索引? ⭐⭐⭐⭐⭐

除了聚簇索引以外:

普通建立的索引通常属于:

二级索引

也叫:

Secondary Index

例如:

CREATE INDEX idx_name
ON user(name);

这里:

idx_name

就是二级索引。


十四、二级索引叶子节点存什么?

假设:

id = 主键

建立:

CREATE INDEX idx_name
ON user(name);

二级索引叶子节点可以粗略理解为:

name

+

主键id

例如:

idx_name:

张三 → id=10

李四 → id=20

王五 → id=30

注意:

它通常不是:

张三
id=10
age=20
address=杭州
phone=...
所有字段

而是:

索引列

+

主键

十五、什么是回表? ⭐⭐⭐⭐⭐

这是非常重要的面试题。

假设:

CREATE INDEX idx_name
ON user(name);

查询:

SELECT *
FROM user
WHERE name = '张三';

第一步:

idx_name二级索引
      ↓
找到张三
      ↓
得到主键
      ↓
id = 10

但是:

SELECT *

需要:

完整行数据

而二级索引:

只有:

name + id

怎么办?

再去:

主键索引

查询一次。

流程:

idx_name B+树
      ↓
找到张三
      ↓
得到id=10
      ↓
主键B+树
      ↓
找到id=10
      ↓
得到完整数据

这个过程:

叫做回表。


十六、为什么叫“回表”?

可以简单理解:

第一次:

通过二级索引

↓

只拿到主键

数据还不够。

于是:

拿着主键

↓

再回到聚簇索引

↓

找到完整行数据

所以叫:

回表

十七、主键索引 vs 二级索引 ⭐⭐⭐⭐⭐

主键索引

主键B+树

↓

叶子节点

↓

完整行数据

例如:

SELECT *
FROM user
WHERE id = 10;

流程:

主键索引

↓

完整数据

二级索引

二级索引B+树

↓

叶子节点

↓

索引列 + 主键

例如:

SELECT *
FROM user
WHERE name = '张三';

可能:

二级索引
   ↓
主键ID
   ↓
主键索引
   ↓
完整数据

所以:

二级索引查询

可能产生回表

十八、为什么二级索引存主键?

假设:

张三

对应完整数据:

id = 10
name = 张三
age = 20
address = 杭州
...

如果每一个二级索引:

都保存完整数据:

idx_name保存一份完整数据

idx_age又保存一份完整数据

idx_phone又保存一份完整数据

会造成:

大量数据重复

↓

占用大量空间

所以 InnoDB 二级索引:

通常保存:

索引列

+

主键

需要完整数据时:

再通过主键查

十九、一个表有几个聚簇索引?

一个 InnoDB 表:

只有一个聚簇索引

因为:

数据本身只能按照一种聚簇索引结构组织。

但是:

二级索引

可以有多个

例如:

CREATE INDEX idx_name ON user(name);

CREATE INDEX idx_age ON user(age);

CREATE INDEX idx_phone ON user(phone);

可以理解:

user表

├── 聚簇索引
│     └── 主键id
│
├── 二级索引
│     └── name
│
├── 二级索引
│     └── age
│
└── 二级索引
      └── phone

二十、没有主键怎么办?

InnoDB 需要选择一个:

聚簇索引

通常可以这样理解:

有主键
 ↓
使用主键

如果没有主键:

选择合适的唯一非空索引

如果还没有:

InnoDB生成隐藏的行ID

↓

作为聚簇索引键

所以实际开发中:

一般推荐显式创建主键。


二十一、为什么推荐主键不要太大?

因为二级索引:

叶子节点

↓

需要保存主键值

假设一个表:

有5个二级索引

主键越大:

每个二级索引

↓

都要保存更大的主键

可能导致:

索引占用空间增加

所以:

主键通常适合选择比较短、稳定的值。


二十二、完整结构图 ⭐⭐⭐⭐⭐

假设:

user

id   name   age

1    张三    20

2    李四    25

3    王五    30

主键:

id

普通索引:

name

那么:

             user表
                │
       ┌────────┴────────┐
       ↓                 ↓
   主键索引            idx_name
       ↓                 ↓
   聚簇索引            二级索引
       ↓                 ↓
叶子节点完整数据      叶子节点
                         ↓
                     name + id

查询:

SELECT *
FROM user
WHERE id = 2;

流程:

主键索引
   ↓
id=2
   ↓
完整数据

查询:

SELECT *
FROM user
WHERE name = '李四';

流程:

idx_name
   ↓
李四
   ↓
id=2
   ↓
主键索引
   ↓
完整数据

后面这个:

二级索引
   ↓
主键索引

就是:

回表

二十三、为什么 SELECT * 可能增加回表?

例如二级索引:

CREATE INDEX idx_name
ON user(name);

执行:

SELECT *
FROM user
WHERE name = '张三';

二级索引只有:

name

+

id

但是你需要:

*

也就是:

age

address

phone

...

因此:

二级索引数据不够

↓

需要回表

这也是为什么:

实际开发中不建议无脑 SELECT *。

后面学习:

覆盖索引

以后这个问题会更清楚。


二十四、索引完整知识链

目前先掌握:

索引
 ↓
B+ Tree
 ↓
为什么使用B+树?
 ↓
树矮 + 叶子节点有序连接
 ↓
提高查询效率 + 适合范围查询

然后:

InnoDB索引
       ↓
┌──────┴──────┐
↓             ↓
聚簇索引     二级索引
↓             ↓
主键索引     普通索引
↓             ↓
完整行数据   索引列+主键
               ↓
            需要完整数据
               ↓
             回表

🎤 面试回答:为什么 MySQL 使用 B+ Tree?

可以回答:

InnoDB 索引主要使用 B+ Tree。B+ Tree 一个节点可以保存多个索引项,因此树的高度比较低,可以减少查询过程中需要访问的数据页数量。

同时 B+ Tree 的叶子节点按照索引顺序组织并相互连接,因此不仅适合等值查询,也非常适合范围查询。


🎤 面试回答:什么是聚簇索引?

可以回答:

InnoDB 的聚簇索引叶子节点保存完整的行记录,通常主键索引就是聚簇索引。

因此通过主键查询时,找到聚簇索引的叶子节点就可以获得完整的数据。


🎤 面试回答:什么是回表?

可以回答:

InnoDB 的二级索引叶子节点通常保存索引列和主键值。

如果查询需要二级索引中没有的字段,就需要先通过二级索引找到主键,再通过主键聚簇索引查询完整行数据,这个过程叫做回表。


🎯 面试追问

Q1:什么是索引?

答:

帮助数据库快速查找数据的数据结构,可以理解成数据库的目录。


Q2:InnoDB 索引主要使用什么结构?

答:

B+ Tree

Q3:为什么 B+ Tree 查询快?

答:

一个节点可以保存多个索引项

↓

树比较矮

↓

减少需要访问的数据页数量

Q4:为什么 B+ Tree 适合范围查询?

答:

因为:

叶子节点有序

+

叶子节点之间相互连接

找到范围起点后:

可以继续顺序扫描。


Q5:什么是聚簇索引?

答:

叶子节点保存完整行记录的索引,InnoDB 通常使用主键索引作为聚簇索引。


Q6:一个表可以有几个聚簇索引?

答:

一个

Q7:一个表可以有多个二级索引吗?

答:

可以

Q8:二级索引叶子节点存什么?

答:

通常:

索引列

+

主键值

Q9:什么是回表?

答:

二级索引
   ↓
得到主键
   ↓
主键聚簇索引
   ↓
查询完整数据

Q10:主键查询需要回表吗?

通常:

不需要

因为:

主键聚簇索引叶子节点

↓

已经保存完整行数据

Q11:二级索引查询一定回表吗?

不一定。

如果二级索引已经包含:

查询所需要的全部数据

就可能:

不需要回表

这就是后面要学的:

覆盖索引

Q12:索引是不是越多越好?

不是。

索引:

提高查询效率

但是:

占用空间

+

增加INSERT / UPDATE / DELETE维护成本

⚠️ 易错点

1. 索引不是越多越好

索引多
 ↓
查询可能更方便

但是
 ↓
写操作维护成本增加

2. 二级索引不是一定回表

错误:

二级索引查询
=
一定回表

正确:

查询需要的字段
二级索引已经全部包含

↓

可以不回表

这就是:

覆盖索引

3. 聚簇索引不是单独存一份“索引 + 数据文件”

可以简单理解:

聚簇索引的叶子节点

↓

就是完整行记录

4. B+ Tree 不只是为了等值查询

它还非常适合:

范围查询

排序

顺序扫描

❓ 自测

  1. 什么是索引?

  2. 为什么数据库需要索引?

  3. InnoDB 索引主要使用什么数据结构?

  4. 为什么 B+ Tree 的树比较矮?

  5. 树比较矮有什么好处?

  6. B+ Tree 的非叶子节点主要干什么?

  7. B+ Tree 的数据主要在哪里?

  8. 为什么 B+ Tree 适合范围查询?

  9. 什么是聚簇索引?

  10. InnoDB 主键索引的叶子节点存什么?

  11. 什么是二级索引?

  12. 二级索引的叶子节点通常存什么?

  13. 什么是回表?

  14. SELECT * 为什么容易产生回表?

  15. 主键查询为什么通常不需要回表?

  16. 二级索引查询一定需要回表吗?

  17. 一个 InnoDB 表有几个聚簇索引?

  18. 一个表可以有多个二级索引吗?

  19. 为什么主键不建议设计得特别大?

  20. 没有主键时 InnoDB 怎么选择聚簇索引?

  21. 为什么索引不是越多越好?


评论