在日常工作中,对于慢查询的治理方法之一就是增加索引,索引的使用和学习在开发中是比较重要的内容,希望这篇文章能够彻底的梳理清楚。
索引的分类
索引的本质其实是一种数据结构,索引是在存储引擎层而不是在服务层实现的,所以没有统一的索引标准。其分类可以按照数据结构去分类,也可以按照物理存储进行分类,如下所示:
- 按照数据结构分类:B+Tree 索引、Hash 索引和 Full-text 索引
- 按照物理存储分类:聚集型索引和非聚集型索引
- 按照逻辑分类:主键索引、唯一索引、联合索引
以下将重点介绍 B+Tree 索引、Hash 索引、聚集型索引和非聚集型索引
B+Tree 索引
一般我们说索引如果没有特指就是说 B+Tree 索引。基本上所有的存储引擎都支持它,InnoDB 和 MyISAM 存储引擎默认是 B+Tree 索引。
为什么默认使用 B+Tree 数据结构,而不是 B-Tree 或者是红黑树等数据结构?我们先看下 B+Tree 的数据结构
- B-Tree 索引非叶子节点存储数据,而 B+Tree 索引叶子结点不存储数据,只有在叶子结点存储数据,相对来说,相同层级存储的索引更多。相同也比红黑树的层级要低,层级低代表次数更少的 I/O 操作。
- 叶子结点采用连环式数据结构,可以进行范围查找
Hash 索引
Memory 存储引擎默认是 Hash 索引。Hash 索引的原理是给某列增加索引时,将这列数据进行 Hash 计算得到 Hash 值排列到 Hash 数组中,Hash 索引可以一次性定位到数据,其效率很高。Hash 索引虽然不需要多次进行磁盘 IO,但其也有一些缺点:
- 不能进行范围查找。Hash 索引计算的是经过 Hash 处理过的值,只能进行等式比较,不能用于范围查找,比如使用 order by 查询。
- 不支持最左匹配(不可使用部分索引进行查询)。每次计算需要扫描整个索引表,最左匹配是可以进行索引前缀进行查询,不必扫描整张索引表。
- Hash 索引值大量重复且数据量非常大时,其效率并没有 B+Tree 索引高
聚集型索引和非聚集型索引
聚集型索引和非聚集型索引都是使用 B+Tree 数据结构。
聚集型索引:是指在叶子结点存储完整的行数据,一张表只能有一个聚集型索引,一般是以主键为聚集型索引,如果新建表没有主键,则会创建一个隐含列(唯一)为聚集型索引。
非聚集型索引(辅助索引):叶子结点存储的不是完整的行数据,而是存储一个地址,一般是聚集型索引的地址,通过这个地址能找到聚集型索引,通过聚集型索引再找到完整的行数据。一个表可以有多个非聚集型索引。使用非聚集型索引查询,如果索引中包含查询的列,则直接返回,否则需要回表通过非聚集型索引找到其他查询数据。
联合索引查询
联合索引是指上文中提到的非聚集型索引,也就是辅助索引。联合索引是指索引中包含多个列,举个例子,假如建立索引如下所示:
sql
alter table index_example add index idx_union(`name`, `age`, `position`);
数据存储的结构如下所示:
索引的存储会分别按照 name、age 和 position 排序,如果 name 相同,则根据 age 进行排序,name 和 age 相同,则根据 position 进行排序。
应该如何加索引
我们上面介绍了索引包括原理等一些基本情况,在日常开发中,加索引也有一些原则需要注意。以下是加索引的基本原则:
- 不要在数据量比较小的表建立索引。在查询时存储引擎会进行判断是否需要使用索引,数据量较小的表可能不会使用索引。
- 选择唯一主键索引。如果可以尽量使用主键索引或者唯一索引,将会更快的定位到数据(不需要回表)。
- 为经常需要排序、分组和联合操作的字段建立索引。group By、order by、distinct 和 union 等查询操作。
- 加索引要满足最左匹配原则。
- 尽量选择区分度高的字段增加索引。性别字段就不适合增加索引,不重复的比例越大,扫描的行数越少。索引是根据字段进行排序,0 和 1 的区别不大。
- 对字段使用函数不会走索引。
segmentfault.com/a/119000003...