一篇文章告诉你什么是索引?
什么是索引?
索引的定义是帮助存储引擎快速获取数据的一种数据结构,形象地说,索引就是数据的目录。
索引的分类
可以从四个角度来分类索引:
| 分类角度 | 索引类型 |
|---|---|
| 数据结构 | B+Tree索引、Hash索引、Full-text索引 |
| 物理存储 | 聚簇索引(主键索引)、二级索引(辅助索引) |
| 字段特性 | 主键索引、唯一索引、普通索引、前缀索引 |
| 字段个数 | 单列索引、联合索引 |
按数据结构分类
InnoDB存储引擎在不同场景下选择不同的列作为索引:
有主键:使用主键作为聚簇索引的索引键
无主键:选择第一个不包含NULL值的唯一列
都没有:自动生成隐式自增id列
B+Tree索引查询过程示例:
查询过程自顶向下逐层查找,经历3个节点即3次I/O操作。
二级索引与回表:
二级索引的叶子节点存放的是主键值,而非实际数据
使用二级索引查询需要先查二级索引获得主键值,再查主键索引获取完整数据,这个过程叫"回表"
如果查询的数据能在二级索引中直接获取,则称为"覆盖索引",无需回表
为什么MySQL InnoDB选择B+Tree?
| 对比项 | B+Tree优势 |
|---|---|
| vs B树 | 非叶子节点不存数据,单节点数据量更小,I/O次数更少;叶子节点双向链表适合范围查询 |
| vs 二叉树 | 高度维持在3~4层,千万级数据只需3~4次I/O |
| vs Hash | Hash不适合范围查询,B+Tree适用范围更广 |
按物理存储分类
| 类型 | 叶子节点存储内容 |
|---|---|
| 聚簇索引(主键索引) | 实际数据 |
| 二级索引(辅助索引) | 主键值 |
按字段特性分类
1. 主键索引
2. 唯一索引
3. 普通索引
4. 前缀索引(对字符类型字段的前几个字符建立索引)
按字段个数分类
联合索引
联合索引的B+Tree先按第一个字段排序,在第一个字段相同的情况下再按第二个字段排序,以此类推。
最左匹配原则:使用联合索引时,需按照最左优先的方式进行索引匹配,否则索引会失效。
联合索引范围查询的特殊情况:
| 查询条件 | 索引使用情况 |
|---|---|
a > 1 and b = 2 | 只有a用到索引,b用不到(>会停止匹配) |
a >= 1 and b = 2 | a和b都用到了索引(>=不会停止匹配) |
a BETWEEN 2 AND 8 AND b = 2 | a和b都用到了索引 |
name like 'j%' and age = 22 | name和age都用到了索引 |
索引下推(MySQL 5.6+)
在没有索引下推时,二级索引查询需要先回表再判断条件。使用索引下推后,可以在联合索引遍历过程中先对索引中包含的字段做判断,直接过滤不满足条件的记录,减少回表次数。执行计划中出现Using index condition即表示使用了索引下推。
索引区分度
区分度 = 字段不同值的个数 ÷ 表的总行数
建立联合索引时,应把区分度大的字段排在前面。
联合索引用于排序
什么时候需要/不需要创建索引?
适用索引的场景
字段有唯一性限制(如商品编码)
经常用于WHERE查询条件的字段
经常用于GROUP BY和ORDER BY的字段
不需要创建索引的场景
WHERE、GROUP BY、ORDER BY里用不到的字段
字段中存在大量重复数据(如性别字段)
表数据太少
经常更新的字段
优化索引的方法
1. 前缀索引优化
使用字符串字段的前几个字符建立索引,可减小索引字段大小,提高查询速度。但无法用于ORDER BY和覆盖索引。
2. 覆盖索引优化
索引的叶子节点上包含查询所需的所有字段,可避免回表操作,减少I/O。
3. 主键索引最好是自增的
自增主键的好处:
每次插入新数据是追加操作,不需要移动已有数据
避免页分裂,提高插入效率
减少内存碎片,提高查询效率
4. 索引最好设置为NOT NULL
NULL会使优化器在选择索引时更加复杂
NULL会占用物理空间(需要NULL值列表)
5. 防止索引失效
常见索引失效的情况:
使用左模糊或左右模糊匹配(
like %xx或like %xx%)对索引列做了计算、函数、类型转换操作
违反联合索引的最左匹配原则
OR条件中只有部分列是索引列
执行计划关键指标
| 字段 | 说明 |
|---|---|
| possible_keys | 可能用到的索引 |
| key | 实际使用的索引(NULL表示未使用索引) |
| key_len | 索引长度 |
| rows | 扫描的数据行数 |
| type | 数据扫描类型(性能从低到高:All → index → range → ref → eq_ref → const) |
Extra字段重要指标:
Using filesort:需要文件排序,效率低Using temporary:使用临时表,效率低Using index:使用了覆盖索引,效率高
总结
| 问题 | 答案 |
|---|---|
| 什么是索引? | 帮助存储引擎快速获取数据的数据结构 |
| 常用索引类型? | B+Tree、Hash、Full-text;聚簇、二级;主键、唯一、普通、前缀;单列、联合 |
| 为什么用B+Tree? | 查询效率高,I/O次数少,适合范围查询 |
| 什么是回表? | 使用二级索引查询后,再查主键索引获取完整数据 |
| 什么是覆盖索引? | 查询所需数据都能在索引中直接获取,无需回表 |
| 最左匹配原则? | 联合索引按最左优先方式匹配,遇到>、<会停止匹配(>=、<=、BETWEEN、like前缀不会停止) |
| 主键为什么推荐自增? | 避免页分裂,提高插入效率和空间利用率 |
| 索引失效常见情况? | like左模糊、索引列计算/函数/类型转换、违反最左匹配、OR条件不全为索引列 |
