彻底搞明白MySQL的索引原理

前言

越来越多的公司正在使用MySQL作为数据库来进行数据存储,想必索引(Index)大家也都不会陌生,可能所有的开发人员都知道索引是为了加速数据查询才存在的。无论是在开发中还是面试中,索引出现的频率都是特别的高,所以无论是为了工作还是面试,我们都要搞清楚索引的原理,只有掌握了它的原理才能应付各种问题。接下来我们就简单来了解一下到底MySQL的索引是什么。

索引是什么
索引是为了帮助MySQL存储引擎高效的获取排好序的数据结构。简单一点理解就是快速查找排好序的数据结构,用我们生活中的例子做类比的话就是字典的目录(虽然某些索引类型来讲不是很贴切)。

索引的几个概念:

  1. 主键索引(主索引),顾名思义就是表的主键所建的索引
  2. 辅助索引,就是根据业务的需要,建立的非主键索引统称为辅助索引
  3. 聚簇索引,通俗点就是索引与表数据在一起存储,找到索引就找到了数据,这样的索引我们称之为聚簇索引,一个表只能有一个聚簇索引,因为数据存储的物理地址是唯一的,通常情况下为主键索引,InnoDB存储引擎的主键索引采取的就是聚簇索引。
  4. 非聚簇索引,索引与数据分开存储,通过索引只是找到数据对应的指针,还需要再通过指针去寻找数据,MyISAM的主键索引和辅助索引都采用的是非聚簇索引。

MySQL的索引有哪些
可以作为索引的数据结构有很多,比如:二叉树、红黑树、B-Tree、Hash表、B+Tree等,那么MySQL的索引有哪几种类型呢?MySQL最常用的索引类型有两种:B+Tree和Hash,这里我们把B-Tree这种类型也一起看一下。

B+Tree这种索引的类型其实是在B-Tree的基础上做了升级,算是一个高级进阶版本的B-Tree

索引类型之——B+Tree
介绍B+Tree之前,首先要说一下B-树(B-Tree),学过数据结构的应该都清楚B树的性质,B-树是一棵多路平衡查找树,与二叉树、红黑树想必降低了树的高度,也就相当于降低了IO次数。
在这里插入图片描述
而B+Tree相对于B-树的结构上做了一些改变:

1.每个中间节点不保存数据,只用来索引,也就意味着所有非叶子节点的值都被保存了一份在叶子节点中

2.叶子节点之间根据自身的顺序增加指针做链接
在这里插入图片描述
这样做的好处就是我们查找的次数将会变得更少,因为我们都知道MySQL默认情况下,表空间中的页大小都为 16KB,如果我们只存储索引不存储数据的话,那么显而易见大小相同的情况下B+Tree存储的索引数量将会更大,相同数据量的情况下会减少了树的高度,也就会减少IO的次数,因为IO次数越多我们所需花费的查找成本将越高。

B+Tree的时间复杂度为O(H)=O(logdN)(H为树高, d为出度, N为数据量),假设一棵出度为200,数据量为200万的树,我们可以算出树的高度仅为3,也就意味着我们只需3次IO就可以读取到我们想要查找的数据。

索引类型之—Hash表
Hash索引是基于Hash表实现的,只有查询条件精确匹配hash索引中的所有列的时候,才能用到Hash索引。哈希算法时间复杂度为O(1),且不只存在于索引中,每个数据库应用中都存在该数据结构,由于其特殊的结构,其检索的效率也是非常高,索引的检索可以一次定位,不会像B+Tree那样需要从根节点一直查找到叶子节点这样多次IO才查找到最终需要的数据。Hash表索引类型在开发中用到的场景不多,所以这里不做详细的介绍,如果需要详细了解可以在MySQL官网或者相关的论坛找到详细资料。

B+Tree与Hash索引类型的区别
按照上述所看到的特点Hash索引类型(Memory存储引擎默认索引类型)查询的效率要远远高于B+Tree,可是为什么MySQL的InnoDB和MyISAM默认都采用的是B+Tree来作为索引呢?

接下来我们看看一下Hash索引类型有哪些不足:

  1. Hash索引类型不支持对数据的范围查找。也就是说默认Hash类型对精准查找的效率非常高,但是无法进行范围过滤,因为经过相应的Hash算法处理之后的Hash值的大小关系,并不能保证和Hash运算前完全一样
  2. Hash索引类型无法支持对数据的排序操作。而且Hash值的大小关系并不一定和Hash运算前的键值完全一样,所以数据库无法利用索引的数据避免进行任何排序的操作。
  3. Hash索引类型如果有多列索引,无法支持部分索引列的查询。对于多列的组合索引,Hash索引在计算Hash值的时候是将索引的多列合并后再一起计算Hash值,而不是单独计算Hash值,所以通过组合索引的前面一个或几个索引键进行查询的时候,是无法使用索引的。
  4. Hash索引类型如果遇到大量数据Hash值相等的情况下查询效率会大大下降。如果对选择性较低的列建Hash索引,那么将会存在大量的数据行指针存放于同一Hash值下,想要定位具体数据是非常繁琐的,会浪费多次数据的访问,造成整体查询性能的低下。
  5. Hash索引类型的查找必然会经历两次查找。由于Hash索引的存储方式为Key为索引键的Hash值,Value为行数据的指针,所以一次数据的查询要先查询出数据的指针,再通过指针查询数据,不过一般热点行数据都会有缓存,也不会造成性能低下。
  6. Hash索引类型必然会进行全表扫描。前面已经说过,Hash索引是将索引键通过Hash运算之后,将
    Hash运算结果的Hash值和所对应的行指针信息存放于一个Hash表中,由于不同索引键存在相同Hash值,所以即使取满足某个Hash键值的数据的记录条数,也无法从Hash索引中直接完成查询,还是要通过访问表中的实际数据进行相应的比较,并得到相应的结果。

InnoDB存储引擎的索引实现
InnoDB虽然和MyISAM都是采用的B+Tree来实现的索引,但是InnoDB的索引存储方式和MyISAM还有些不同,之前的文章我们说过这两种存储引擎的文件存储方式不同(MySQL存储引擎),重大区别是 InnoDB 的数据文件本身就是索引文件。

在InnoDB 中,表数据文件本身就是按 B+Tree 组织的一个索引结构,这棵树的叶点data 域保存了完整的数据记录。这个索引的 key 是数据表的主键,因此 InnoDB 表数据文件本身就是主索引。
在这里插入图片描述
上图中的索引就是这张表的主键索引,我们找到索引就找到了数据,我们称这种索引为聚簇索引。

InnoDB存储引擎要求必须有主键索引(聚簇索引的特征),如果没有显示的指定主键索引,那么MySQL会自动选择一个可以唯一标识数据的列作为唯一索引,如果表中没有唯一的列来标识数据的话,那么MySQL将会自动维护一个长整形的隐含字段来作为主键,所以为了能更清晰的显示表的主键,在使用InnoDB作为表的存储引擎时我们最好还是主动创建采用自增的主键。因为 InnoDB 数据文件本身是一棵B+Tree,非单调的主键会造成在插入新记录时数据文件为了维持 B+Tree 的特性而频繁的分裂调整,十分低效,而使用自增字段作为主键则是一个很好的选择。如果表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的页,有益于提高效率。

InnoDB存储引擎中的辅助索引与主键索引唯一不同的地方就是,辅助索引的叶子节点存储的不是数据行,而是对应的主键,所以需要再根据主键查询出具体数据,这种查询方式称为“回表查询”。

MyISAM存储引擎的索引实现
MyISAM都是采用的也是B+Tree来实现的索引,但是由于其数据文件和索引文件是分开进行存储我们称为非聚簇索引。索引都是采用B+Tree索引结构但是与InnoDB存储引擎下还有些许不同。它的叶子节点存储的是将不再是数据而是数据行对应的指针,也就是说MyISAM在查询数据的时候需要先根据索引查找到数据的指针,再根据指针查找数据,相对于InnoDB来说多了一次IO。
在这里插入图片描述
MyISAM存储引擎允许没有任何索引和主键的表存在。MyISAM的主键索引与辅助索引是没有区别的,辅助索引的叶子节点也是存储的数据行的指针,所以不存在“回表查询”的说法。

以上为MySQ索引原理的理解和总结,只有掌握了基本原理才能明白如何去解决问题和优化解决方案,下一篇我们再讲解一下MySQL的索引类型及索引优化的东西。希望这篇文章可以帮助正在学习技术的你,如有不足之处欢迎评论指正,一起学习一起进步!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值