第二十一周_R_MySQL 索引详解

58 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情

索引介绍

索引是存储引擎用于快速找到记录的一种数据结构。是对查询性能优化最有效的手段了。

索引的数据结构

索引底层的数据结构有很多的类型,常见的有:B 树、B+ 树、Hash、有序数据、红黑树等。

哈希索引

简介

哈希索引(hash index) 基于哈希表实现,只有精确匹配索引所有列的查询才有效。对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码,哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针。「类似于 Java 中的 HashMap 」数据很多的情况下,不可避免的会出现哈希码一样的情况,处理这种情况是拉出一个链表。

优缺点

数据结构的特性决定了它的使用限制。

  • 哈希索引只包含哈希值和行指针,而不存储字段值,所以不能使用索引中的值来避免读取行(比如覆盖索引,避免回表就不行)。
  • 数据存放不是按照索引顺序存储,不能用于排序。当然也不能用于范围查找
  • 不支持部分索引列匹配查找,以为它始终是使用索引列的全部内容来计算哈希值的,比如(a,b)建立哈希索引,如果只有 a ,则无法使用索引。
  • 冲突很多的情况下只能挨个遍历链表。「这里可参考 HashMap,它的链表过长会转红黑树」。而且维护的代码也很高。

适用场景

哈希表这种结构适用于只有等值查询的场景。

在 MySQL 中,只有 Memory 引擎显示支持哈希索引。

有序数组

简介

数组的结构就是连续的内存空间,有序就是排序好的,基于下标查找 O(1) 时间复杂度,不适用于中间删除和增加。

优缺点

  • 支持范围查找,使用二分法
  • 不能经常性的增加删除,会挪动很多空间

适用场景

适用于静态存储引擎, 比如保存以前某个城市的某一年的人口。不会再修改的数据。

B+Tree 索引

我们一般说的索引都是 B+ 树索引。MySQL 默认的存储引擎是 InnoDB ,InnoDB 默认的索引是 B+ 树。

  • B+ 树只有叶子节点存放 key 和 data ,其他节点只存放 key。
  • B + 树的叶子节点有一条引用链指向与它相邻的叶子节点。
  • B + 树的检索效率很稳定,任何查找都是从根节点到叶子节点的过程。

具体的 B+ 树结构以及在 MySQL 中使用的详情还有待深入学习,先挖个坑。

索引的类型

主键索引

在 InnoDB 中,主键索引也叫聚簇索引(clustered index)。数据库的主键列使用的就是主键索引。

一张数据库表只能有一个主键,并且主键不能为 null,不能重复。下面你虽然选了两个主键,但是为你创建的是联合主键,所以还是只有一个主键。

在 MySQL InnoDB 中,没有显示指定主键的时,InnoDB 会选择第一个唯一非空的索引代替,如果也不存在这样的索引,那么 InnoDB 会隐士定义一个主键。

非主键索引

在 InnoDB 中,非主键索引也叫二级索引(secondary index)。唯一索引、普通索引、前缀索引等都属于二级索引。

  • 唯一索引:数据不能重复,允许数据为 NULL ,主要不是为了查询效率,而是保证数据唯一性
  • 普通索引:运行数据重复和NULL,单纯为了查询快
  • 前缀索引:只适用于字符串类型。为了节省空间,因为只需要创建前几个字符作为索引。

主键索引 vs 非主键索引

基于这两种索引查询有什么区别?

select * from T where ID = 500   ID 是主键
select * from T where k = 5      k 是普通索引
  • 基于主键索引,只需要搜索 ID 这颗 B+ 树
  • 基于非主键索引,先搜索 k 这颗索引树,得到主键值,再到 ID 索引树搜索一次,这个过程称为回表。

也就是非主键索引的查询需要多扫描一棵索引树。

聚簇索引 vs 非聚簇索引

聚簇索引不是一种单独的索引类型,而是一种数据存储方式。InnoDB 中的聚簇索引就是叶子节点既保存了索引也保存了数据行。 所以主键索引就属于聚簇索引。

非聚簇索引是索引结构和数据分开存放的的索引,二级索引就属于非聚簇索引。

覆盖索引

上面我们提到了回表:当使用二级索引查询的时候,需要回表。那么是否可以避免回表呢?也就是说索引的值‘覆盖’了我们的查询需求,我们就称为覆盖索引。也是常用的优化手段。

最左前缀索引

B+ 树可以利用索引的“最左前缀”来定位记录。一般建立一个联合索引,可以通过调整顺序就可以少维护一个索引。比如说 (a,b)联合索引,此时就不需要再单独建立一个 a 索引了。

索引下推

可以在非聚簇索引遍历过程中,对索引包含的字段先做判断,过滤掉不符合条件的记录,减少回表次数。

总结

目前 InnoDB 中常用的索引理论知识整理了下。还需继续学习:

  • B+ 树结构以及在 MySQL 中的具体使用。

参考

《高性能 MySQL 第三版》

MySQL45讲