从根上开始学习MySql索引(一)

写在最最前面的话

要深入理解MySql的索引知识,那就首先也是必须要先完全理解关于“树”这种数据结构,要不然我们就是看一百遍文章也不明白所以然。所以,如果你还没有完全理解“树”,那么就请先看之前的三篇博客:
[《(一)树(树、二叉树、满二叉树、完全二叉树、二叉搜索树、二叉平衡树、B-Tree、B+Tree)》]
《漫画:什么是B-树?》
《漫画:什么是B+树?》
那么要理解到什么程度呢?

  • 了解树的基本概念及术语;
  • 会构造出二叉树,能够写出树的遍历(先根遍历、中根遍历、后根遍历)
  • 深入理解各种树结构产生的原因,即为什么要出现这样那样的树结构,它与其它树结构有哪些优点和不足
  • 不一定要求能写出B树,但一定要深入理解它的原因,很重要

必须要先完全理解关于“树”这种数据结构
必须要先完全理解关于“树”这种数据结构
必须要先完全理解关于“树”这种数据结构
必须要先完全理解关于“树”这种数据结构
重要的事情说3遍,这里我说四遍。

如果你能够完全掌握上面说的四点,那么就请继续往下看文章吧。其实,如果你真正理解了“树”,其实不看下面的文章也可以,因为你自己就能完全理解MySql的相关索引的内容。

1.SQL查询语句的执行过程

我们来下面这张图,这就是MySql数据库的基本构成及SQL(查询)语句的执行过程。我们根据这个图,简要的说一下这个过程:
在这里插入图片描述

1. MySql的组成

基本上,MySql是由Server层和存储引擎两部分组成。
Server层:主要包括连接器、查询缓存、分析器、优化器、执行器等,包含了MySQL 的大多数核心服务功能,如内置函数、自定义函数、存储过程、触发器、视图等;
存储引擎:主要作用是负责数据的存储和读取,主要包括InnoDB、MyISAM、NDB、Memory 、Infobright 、BLACKHOLE等存储引擎。从MySQL 5.5.8 版本开始是默认的存储引擎是InnoDB,之前的版本默认的存储引擎是MyISAM。关于各种存储引擎,我们不再进行详细的介绍,我们这篇文章主要是基于InnoDB,这也是我们最常用的一个InnoDB。

2.Server层

  • 连接器:管理连接,权限认证
  • 查询缓存:连接建立完成后,首先会执行“查询缓存”,查询缓存是一种k-v结构,key是sql语句,value是查询结果,如果命中后,会直接返回客户端结果。你可能觉得这个功能真是不错,但其实不然,我们大部分时候最好是禁用查询缓存(将参数 query_cache_type 设置成 DEMAND),为什么呢?这是因为查询缓存特别容易失效,只要对一个表的数据有变更,那么与该表有关的所有查询缓存都会被清空,那么我们好不容易建立起的缓存,还没使用几次,就失效了。所以对于更新比较多的数据库,缓存命中的概率就很低了。MySQL 8.0 版本将查询缓存的整块功能去掉了,足以说明它确实意义不大;
  • 分析器:如果没有命中查询缓存,那就要执行SQL了。识别sql语句关键字,判断表是否存在,判断列是否存在,判断sql语句的合法性等,进行预处理;
  • 优化器:决定选用的索引以及表的连接顺序等;
  • 执行器:验证表的执行权限,连接存储引擎的接口,返回查询结果

2.MySql索引

1.索引的概念

索引是为了加速对表中数据行的检索而创建的一种分散的存储结构。索引是针对表而建立的,它是由数据页面以外的索引页面组成的,每个索引页面中的行都会含有逻辑指针,以便加速检索物理数据。索引的出现其实就是为了提高数据查询的效率,就像书的目录一样。

2.几种索引的比较

与其说是索引的比较,其实我认为不如说是几种数据结构的比较。我们这里先说三个比较常见的索引模型:哈希表、有序数组、二叉搜索树、二叉平衡树、B-Tree和B+Tree,来进一步推理出MySql所使用的索引模型(数据结构)。我们以一个简单的学生(S)表为例来说明:

id(学生ID)name(姓名)
1jane
2jack
3john
4bill
5blake
6bob

1.哈希表

哈希表是一种以键 - 值(key-value)存储数据的结构,可以通过key直接获取到value值,它的维护一个数组,把key经过hash之后,确定当前key所在数组的位置,然后把value放在数组这个位置。当不同的key经过hash计算后重复时,这时候在这个位置直接拉出一个链表,来存储各个value。如下图所示:
在这里插入图片描述

从图中我们可以看出,要根据id查询出name,速度是非常快的,但是如果我想查询处在[3,6]这个区间中的学生姓名,那就必须要进行全表扫描了,此时的IO次数就会过多,严重影响了查询的效率(因为id在上面图中并不是有序的,即hash之后的值并不是按照id的真实顺序排列,并且hash的值越分散越好,减少后面的链表元素的数量)。即:哈希表这种结构适用于只有等值查询的场景,比如 Memcached
说明:这里说的无序并不是说id进行hash之后的值在数组中无序,hash值在数组中肯定是有序的,而是说数组中hash值的顺序并不是源id的顺序,即映射到id,那就是无序的。好,既然因为它是无序的,我们就采用有序的,自然就会想到有序数组,那么有序数组可以不可以?我们往下看。

2.有序数组

在这里插入图片描述
有序数组没有什么好说的,我们都清楚的很,平时写代码用的也是最多的一种数据结果。它查询快(即:随机访问效率很高,时间复杂度可以达到O(1),因为数组的内存是连续的,想要访问那个元素,直接从数组的首地址向后偏移就可以访问到了),即便不是放在一块连续的内存中,只要保证是有序的,那我们也可以使用二分法来比较快速的找到,时间复杂度也就在O(log(N)),也并不是不可以接受。那么看似这种结构比较完美了,其实不然,它最大的问题就在于更新和删除的时候,要进行元素的挪动,新增的时候还会涉及到扩容,代价就太高了,即有序数组索引只适用于静态存储引擎
那怎么才能利用二分法的思想,同时又能避免更新和增加时的各种问题呢?很自然,我们想到了之前学到的二叉搜索树。那么二叉搜索树到底可不可以呢?我们继续往下看。

3.二叉搜索树

在这里插入图片描述
关于二叉搜索树的概念及特性,我们这里就不载过多的讨论了(认为大家已经具备了这个知识),我们知道,二叉搜索树会出现左、右子树分布极为不平衡。也就是说,插入的序列越接近有序,生成的二叉搜索树就越像是一个有序链表(是不是也可以理解成一个有序数组?),这样我们要想查询,就和有序数组差不多了。所以我们为了避免这种情况的发生,即让树的结构看起来尽量“均匀”,左右子树的节点数尽量一样多,于是我们就想到了二叉平衡树。那么二叉平衡树到底可不可以呢?我们继续往下看。

4.二叉平衡树(AVL树)

在这里插入图片描述
从图中我看可以看到,二叉平衡树通过二叉搜索树的"旋转",左右节点变得非常均匀,树的高度也变低了,树的高度低了,自然而然我们IO的次数就降低了(加入一个路径就代表依次IO)。到这里,我们似乎已经找到了合适的数据结构,但是MySql真的是利用平衡二叉树来实现的么?如果不是,那优势为什么呢?
我们先分析一个平衡二叉树,它会有什么问题呢?平衡二叉树尽管对二叉树做了很多的改进,但是它无法改变的是随着数据的增多,那么树的节点也会增多,而一个节点最多会只有两个子节点,这样树的高度也会快速的增加,高度增加,那么查询的时候,磁盘IO的次数也就会增加,显示对于我们存储大量数据的MySql来说,是不合适的。唉,到目前为止我们还是没有找到合适的数据结构。别泄气,我们离最终的结果已经相差不远了。
好,下一步我们就要解决树的高度问题,尽可能减少数的高度,那怎么做了?如果看了之前树的各种结构,那么我们自然就会想到利用B-Tree。那么B-Tree底可不可以呢?我们继续往下看。

5.B-Tree

在这里插入图片描述
我们只用了一个三阶B-Tree,树的高度就降低了,试想一下,我们我们扩大阶数,是不是就能更进一步降低我们树的高度,从而更进一步降低IO的次数,提高查询的效率。树相对于平衡二叉树的不同是,每个节点包含的关键字增多了,特别是在B树应用到数据库中的时候,数据库充分利用了磁盘块的原理(磁盘数据存储是采用块的形式存储的,每个块的大小为4K,每次IO进行数据读取时,同一个磁盘块的数据可以一次性读取出来)把节点大小限制为能充分使用在磁盘块大小范围;把树的节点关键字增多后树的层级比原来的二叉树少了,减少数据查找的次数和复杂度。看似几乎完美,但我们知道,MySql并没有采用B-Tree作为它的底层数据结构(我们可以想到最简单的原因,如果一个查询无法命中索引,那就要进行全表扫描,那么这个开销可就大了,它需要对树进行多次的查询),而是采用了它的改进版本B+Tree,这个数据结构我们在之前也做了介绍,下面我们就看一下B+Tree到底行不行?行的话,行在哪里?

6.B+Tree

在这里插入图片描述
和B-Tree相比,B+Tree做了一些改进,使得它更适合做MySql数据库的索引,主要体现在以下几个方面:

  • B+树的层级更少:相较于B-Tree,B+每个非叶子节点不需要存储全部索引,只需要存索引近可以了,所以存储的关键字数更多,树的层级更少,B+树的结构B-Tree更加的“矮胖”,IO次数就更少了,比所以查询数据更快;
  • B+树查询速度更稳定:B+所有关键字数据地址都存在叶子节点上,所以每次查找的次数都相同,而B-Tree只要匹配到要查找的元素即可,无论匹配元素的位置处在哪个非叶子节点,所以查询速度要比B-Tree更稳定;
  • B+树天然具备排序功能:B+树所有的叶子节点数据构成了一个有序链表,在查询大小区间的数据时候更方便,数据紧密性很高,缓存的命中率也会比B-Tree高。
  • B+树全节点遍历更快:B+树遍历整棵树只需要遍历所有的叶子节点即可,,而不需要像B-Tree一样需要对每一层进行遍历,这有利于数据库做全表扫描。

3.小结

上面我们通过对各个常用的数据结构的简单对比,一步一步推理出了这个结论:MySql的索引是采用B+Tree这种数据结构。下一篇文章,我们将具体介绍一下MySql的各种索引,以便对此有个全面更细致的了解,下一篇再见了哦。
有不正之处,请多多予以指正。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值