MySQL索引

541 阅读6分钟

基础

什么是索引

索引是关系数据库中对某一列或多个列的值进行预排序的数据结构。

索引的作用

索引的是用于数据查找的一种数据结构,常见的用于数据查找的数据结构,有有序数组、二叉查找树、哈希表等,这些数据结构都是查找速度较快的。

面临的问题

索引设计面临如下几个问题:

  • 如何更快的查询到数据;
  • 是否支持范围查询;
  • 如何减少空间的占用;
  • 如何减少磁盘的交互次数,因为数据最终都是存放在磁盘上的,与磁盘的交互阅读速度越慢;
  • ……

实现方式

B-Tree/B+Tree

概念:B-Tree指的是B树,“-”并非减符号,而B+Tree指的是B+树。

在讲解B树和B+树前,让我们思考一个问题,常见的有序数组、二叉查找树等的查询速度都是log(n),而我们知道MySQL中InnoDB引擎,默认使用的是B+树作为索引的结构,为什么呢?

我们知道,内存是不安全的易失性存储,而磁盘才是持久性的存储介质。而且,由于价格因素,磁盘才是最主要的用于数据存储的,大部分的数据,其实是处于磁盘中,而非内存中的。而如果使用有序数组,尽管查找速度是log(n),但每次查找数据,都需要在磁盘中进行log(n)次的磁盘访问,访问速度是很慢的。同理,使用二叉树也存在同样的问题,大部分的数据都存在于磁盘中,多次访问磁盘的空间效率更低。那么,B树呢?

B树

B树结构如上图所示,可以看到,B树是一棵多叉查找树树,一个节点可以拥有两个以上的节点。相比于二叉树而言,B树最大的优点在于中间层可以存放于内存中,且相同数据量的情况下,B树的高度低于二叉树,可以减少查找的过程,从而加快存储速度。因此,B树常用于数据库和文件系统的设计中。

上图所示是B+树的结构,B+树是一种类似于B树的结构,B+树与B树的区别有如下几点:

  • B树的非叶子节点上也有完整的行数据,B+树只在叶子节点上有数据,非叶子节点上只有键,优点是内存中存放的键数量更多,查找更快。
  • B+树的叶子节点上包含所有的键,B树的叶子节点上不一定有所有的键。
  • B+树的叶子节点通过链表进行连接,范围查询更加快速。

hash索引

hash索引

MySQL中的hash索引,如上图所示,是基于hash表实现的,使用拉链法来处理数据冲突,hash索引的检索效率非常高,而hash索引也存在一些缺点:

  • hash索引无法处理范围查询,范围查询速度较慢;
  • hash索引无法避免排序运算;
  • hash索引不能利用部分索引键查询,组合索引的场景下,hash索引需要将多个索引键进行合并计算hash值,无法单独利用;
  • hash索引不可避免地存在表扫描地情况,即使通过hash定位到数据,仍然需要对原始数据进行对比,才可以查找到正确地数据;
  • hash索引在大量hash值相等地情况下,性能并不一定比B-Tree索引高。

由于存在以上缺点,即使hash索引的查找速度很快,在使用时却也不一定比B+Tree更好。

索引分类

索引类型

主键索引

数据库表中一列或列组合(字段)的值唯一标识表中的每一行。该列称为表的主键。在数据库中,当定义主键时,会自动创建主键索引,主键索引是唯一索引的特定类型。

普通索引

最基本的索引类型,没有唯一性之类的限制。

唯一索引

唯一索引是不允许其中任何两行具有相同索引值的索引。

聚簇索引/非聚簇索引

聚簇索引:也称聚集索引。表中行的物理顺序与键值的逻辑(索引)顺序相同。一个表只能包含一个聚集索引。

非聚簇索引:也称非聚集索引。在非聚集索引中,数据库表中记录的物理顺序与索引顺序可以不相同。一个表中只能有一个聚集索引,但表中的每一列都可以有自己的非聚集索引。

联合索引

联合索引是由多个字段组成的索引。其中,只有第一个字段是有序的,其他字段仅在前面字段相等的情况下有序,但从整体的角度而言,是无序的。

性能优化

回表

在MySQL中,会自动为主键创建主键索引,同时,主键索引上包含所有的数据。而对于其他的所有非主键索引,非主键索引中只包含索引键和主键数据。因此在非主键索引上查询到主键后,需要通过该主键在主键索引上查找数据,这个过程称为“回表”。

覆盖索引

如上,当select语句查询的内容,在非主键索引上就已经全部包含,不需要再进入主键索引查找时,称为“覆盖索引”。

索引下推

索引查询时时常带有where语句,当多个条件并列,且条件在索引数据中包含时,MySQL会使用“索引下推”在索引上进行匹配,过滤以减少数据,加快查询速度。

最左前缀匹配

最左前缀匹配原则,是一个应用于联合索引的非常重要的原则,即查询时,会按照联合索引建立的顺序,从左到右进行匹配。可以通过以下这几个特性来理解。

  • 对于联合索引,MySQL 会一直向右匹配直到遇到范围查询(> , < ,between,like)就停止匹配。比如 a = 3 and b = 4 and c > 5 and d = 6,如果建立的是(a,b,c,d)这种顺序的索引,那么 d 是用不到索引的,但是如果建立的是 (a,b,d,c)这种顺序的索引的话,那么就没问题,而且 a,b,d 的顺序可以随意调换。
  • = 和 in 可以乱序,比如 a = 3 and b = 4 and c = 5 建立 (a,b,c)索引可以任意顺序。
  • 如果建立的索引顺序是 (a,b)那么直接采用 where b = 5 这种查询条件是无法利用到索引的,这一条最能体现最左匹配的特性。