第四章、Hash表和B+Tree详解

讲MySQL索引之前,需要先了解数据结构Hash表和B+Tree,不然的话,看创建索引的文章等下会一脸懵的。

第一章、MySQL基础架构
第二章、buffer pool缓冲池详解
第三章、MySQL日志详解
第四章、Hash表和B+Tree详解
第五章、全面解析MySQL索引
第六章、InnoDB引擎详解
第七章、MySQL事务的脏读,不可重复读,幻读
第八章、关于MySQL各种锁的详解


数据结构

哈希表

概念

哈希表(Hash Table,也称为散列表),是根据关键字值(key,Value)而直接访问的数据结构。也就是说,它通过把关键字(关键字根据Hash算法生成)映射到表中的一个位置来访问记录,以加快查找的速度。这种映射函数叫做哈希函数,存放记录的数据叫做哈希表。

哈希函数,散列函数都是一个概念

哈希表、散列表也是一个概念,叫法不同而已

简单点说,哈希索引就是采用哈希算法,将键换算成哈希地址,检索时不需要类似B+Tree那样,从根节点到叶子节点逐级查找,只需要根据哈希地址,就能定位到查找的数据,等值查找的情况下,效率非常快。

等值查找:select * from user where user_name = ‘张三’;等于号直接定义的过滤条件,为等值查找

数据的哈希地址 = f (关键字的值),哈希地址只是表示在查找表中的存储位置,而不是实际的物理存储位置。f()是一个函数,通过这个函数可以快速求出该关键字对应的的数据的哈希地址,称之为“哈希函数”。

简单说:哈希表就是让key通过哈希函数,算出数组的索引,然后将value存储在该位置上,后面直接通过索引查找。

优点

哈希表可以通过关键字直接找到数据的存储位置,不需要进行遍历比较查找

哈希函数

构建哈希表的时候,最重要的就是哈希函数,不同哈希函数应用于不同的场景。哈希函数主要有:直接定址法、数字分析法、平方散列法、折叠法、除法散列法、随机数法

常用的

  • 除法散列法:H(key) = key % p (p <= m,m是哈希表的长度,避免哈希出来的索引大于哈希表的长度)

哈希碰撞

概念

哈希表的建立,不可避免会存在多个键同时被哈希到一个索引值的情况,这种就叫做哈希碰撞

处理哈希碰撞的方法

  • 开放定址法 H(key) = (H(key) + d) % m,(m为哈希表的长度,d是一个增量),当得出的哈希地址冲突时,有三种方法可以获的d的值,然后继续计算,直到计算出的哈希地址不再冲突为止。三种方法为:

    • 线性探测法:d = 1,2,3,… m - 1的情况,即为 i ++ 的情况
    • 二次探测法:d = 12,-12,22,-22 … < m 的情况
    • 伪随机探测法:d = 伪随机数的情况
  • 再哈希法:冲突使用另外一个哈希函数计算,直到冲突不再发生为止

  • 链地址法:将所有存在冲突的关键字所对应的数据全部存储在一个线性链表中。常用!

  • 建立公共溢出区

    建立两张表,一张为基本表,另一张为溢出表。基本表存储没有发生冲突的数据,当关键字由哈希函数生成的哈希地址存在冲突时,就将数据填入溢出表中。

关于哈希表与B+Tree的一些思考

哈希表和B+Tree的区别

  1. 查询条件的区分,如果是等值查询的情况,哈希表的效率比较高,只需要一次查询就能获取到值,这种是建立在key,value都是唯一的情况,如果不是,则需要找到哈希地址(也就是索引),然后在遍历链表查询。如果是范围查询的情况,B+Tree的效率比较快。
  2. 存在重复键值的情况,哈希表需要处理哈希碰撞,效率低

非线性存储结构

树结构

树结构是一种非线性存储结构的数据结构,存储的是具有一对多关系的数据元素的集合。

img

图中使用树结构存储的集合{A,B,C,D,E,F,G,H,I,J,K,L,M},对于数据A来说,和数据B,C,D有关系;对于数据B来说,和数据E,F有关系。这就是一对多关系。

将一对多关系进行存储,整个数据结构存储方式上看,类似生活中的倒着的树,所以这种数据结构叫做树型存储结构。

树节点

结点: 使用树型数据结构存储的每一个数据元素都被称为结点。例如:图中数据元素A就是一个结点。

父结点、子结点、兄弟结点:对于图中的结点A、B、C、D来说,A就是B、C、D结点的父结点(也叫双亲结点),而B、C、D 都是A结点的子结点(也叫孩子结点)。对于B、C、D来说,他们都有共同的父结点,所以他们互为兄弟结点

**叶子结点:**如果结点没有任何子结点的情况,那么该结点被称之为叶子结点。如图中的K、L、F、G、M、I、J 都是这棵树的叶子结点

根结点: 每一个非空树有且只有一个被称为根的结点。如图中,结点A就是整棵树的根结点

子树和空树

**子树:**图中,整个树的根结点是结点A,如果单看结点B、E、F、K、L组成的部分,也是一棵树,而且结点B是这棵树的根结点。所以称B、E、F、K、L这几个结点组成的树为整棵树的子树;同样,结点E、K、L也是一棵树,根结点为E。

树的定义可以为:树是由根节点和若干颗子树构成的

**空树:**如果集合本身是空的,那么构成的树就被称为空树,空树中没有结点。

结点的度和层次

度: 对于一个结点,拥有的子树数(结点有多少分支)称为结点的度。如图中,根结点下有3个子树,所以结点A的度为3。简单说,度就是当前这棵树中,父结点底下有多少个子结点,以最多数量的子结点为准,就是度

一棵树的度是树内各结点的度的最大值,如图中表示的树中,各个结点,最大的度的值为3,所以该树最大的度为3

**结点的层次:**个人认为是深度,图中,A结点为第一层,A结点的子结点B、C、D为第二层,E、F、G、H、I、L为第三层,K、L、M为第四层,一棵树的深度(高度)是树中结点所在的最大的层次,图中树的深度为4

有序树和无序树

如果树中结点的子树从左到右看,谁在左边谁在右边,是由顺序的,那么就是有序树,反之就是无序树。

二叉树

满足一些条件的,便是二叉树

  1. 本身树有序树
  2. 树中各个结点的度不能超过2,即只能是0、1、2

二叉树示意图


二叉树又分为满二叉树和完全二叉树

满二叉树:树中除了叶子结点,每个结点的度都为2,则此二叉树为满二叉树

满二叉树示意图


完全二叉树

有序树,并且除去最后一层结点,则此二叉树被称为完全二叉树

完全二叉树示意图

二叉查找树(二叉排序树)

满足一些条件的,就是二叉查找树

  1. 如果二叉查找树有左结点,那么左结点所有结点的值小于根结点的值
  2. 如果二叉查找树有右结点,那么右结点所有结点的值大于根结点的值
  3. 二叉查找树的左右子树也要求是二叉查找树

img


二叉查找树查找关键字

  1. 如果相等,查找成功直接返回
  2. 如果比较时小于根结点,则说明该关键字可能存在左结点中
  3. 如果比较时大于根结点,则说明该关键字可能存在右结点中

二叉查找树插入关键字

插入的元素一定是位于二叉查找树的叶子结点,并且是一定查找失败时访问的最后一个结点的左孩子或者右孩子。

总结

在二叉查找树做查询操作的时间复杂度,同建立的二叉树本身的结构有关。即使查找表中各数据元素完全相同,但是不同的排列顺序,构建出的二叉查找树是不相同的。也就是说,排序的结构不同,对查找关键字的效率也是不一样的。

例如:查找表 {45,24,53,12,37,93} 和表 {12,24,37,45,53,93}

img

使用二叉查找树实现动态查找操作的过程,实际上就是从二叉查找树的根结点到查找元素的结点的过程。所以时间复杂度同二叉查找树的深度有关,深度越深,时间复杂度越大。

为了弥补二叉查找树,同样元素构造不同的结构的情况下,采用了 平衡化处理,也就是使用一些算法,让二叉查找树变成一颗二叉平衡树。

平衡二叉树(AVL树)

满足以下条件的,就是平衡二叉树

  1. 在符合二叉查找树的条件下,任意两个子树中的左子树和右子树不能超过1

索引

左边是AVL树,它的任何结点的两个子树,比如左子树和右子树,两者比较深度不会超过1,左边是4,右边是3,4-3等于1,没超过1

右边的不是AVL树,它的任何结点的两个子树,比如左子树和右子树,左子树的深度为3,右子树的深度为1,超过了1,因此不是平衡二叉树

插入或删除会导致AVL树失去平衡,具体可以概括为LL(左左),LR(左右),RL(右左),RR(右右) 这四种。


B-Tree (多路平衡查找树)

B-Tree是为磁盘设备设计的一种平衡查找树。

系统从磁盘读取数据到内存,是以磁盘块(block)为基本单位的,位于同一个磁盘块中的数据会被一次性取出来,而不是需要什么取什么。

InnoDB存储引擎中有页(Page)的概念,页是其磁盘管理的最小单位。InnoDB存储引擎中默认每个页的大小为16KB,可通过参数innodb_page_size将页的大小设置为4K、8K、16K,在MySQL中可通过如下命令查看页的大小:

show variables like 'innodb_page_size';

而系统一个磁盘块的存储空间往往没有这么大,因此InnoDB每次申请磁盘空间时都会是若干地址连续磁盘块来达到页的大小16KB。InnoDB在把磁盘数据读入到磁盘时会以页为基本单位,在查询数据时如果一个页中的每条数据都能有助于定位数据记录的位置,这将会减少磁盘I/O次数,提高查询效率。

满足以下条件的,就是B-Tree

  1. 根结点至少有两个子女
  2. 每一个结点最多包含K个孩子,K的大小取决于磁盘页的大小。

索引

每个节点占用一个盘块的磁盘空间,一个节点上有两个升序排序的关键字和三个指向子树根节点的指针,指针存储的是子节点所在磁盘块的地址。两个关键词划分成的三个范围域对应三个指针指向的子树的数据的范围域。

以根节点为例,关键字为17和35,P1指针指向的子树的数据范围为小于17,P2指针指向的子树的数据范围为17~35,P3指针指向的子树的数据范围为大于35。

模拟查找关键字29的过程:

  1. 根据根节点找到磁盘块1,读入内存。【磁盘I/O操作第1次】
  2. 比较关键字29在区间(17,35),找到磁盘块1的指针P2。
  3. 根据P2指针找到磁盘块3,读入内存。【磁盘I/O操作第2次】
  4. 比较关键字29在区间(26,30),找到磁盘块3的指针P2。
  5. 根据P2指针找到磁盘块8,读入内存。【磁盘I/O操作第3次】
  6. 在磁盘块8中的关键字列表中找到关键字29。

分析上面过程,发现需要3次磁盘I/O操作,和3次内存查找操作。由于内存中的关键字是一个有序表结构,可以利用二分法查找提高效率。而3次磁盘I/O操作是影响整个B-Tree查找效率的决定因素。B-Tree相对于AVLTree缩减了节点个数,使每次磁盘I/O取到内存的数据都发挥了作用,从而提高了查询效率。

总结:说到底,B-Tree就是将原先一个结点只能存储一个值的情况,改为一个结点可以存储多个值,因为查找的时候,需要将数据从磁盘中读取到内存里面,一旦磁盘IO次数过多,就会造成查询缓慢,所以这里存储多个值,可以一次性读取相近的值,从而避免查询多次IO,将查询操作放到内存里面。内存执行效率可以忽略不计。

再简单说,举个例子,数据库有10条数据,id为1,2,3…10,以前要查询第10条,我查询数据库10次,然后for循环到第10条(对应二叉树);现在不用了,现在我把1,2,3…10直接查出来,放到内存里面,直接从内存里面比较然后拿出来(对应B-Tree)

缺点: 结点中的数据,不仅存储了key,还存储了value值,而这些数据是存储在页中的,每一页为16KB,页存储的空间是有限的,所以有可能存在,每一个结点,只存储了一个key和value就存不下去了,也就是变成了二叉树的数据结构。深度一样,磁盘IO树也是一样了。所以又衍生出了B+Tree。

B+Tree

B+Tree是B-Tree的一种优化,更适合实现外存储索引结构,InnoDB就是用B+Tree实现索引结构。

满足以下条件,就是B+Tree

  1. 非叶子结点,不保存数据,只保存索引;所有的数据都保存在叶子结点中
  2. 叶子结点中,保存所有数据的信息,及指向含这些元素记录的指针,并且叶子结点本身根据关键字的大小自小而大顺序链接,是一个链表结构。
  3. 每一个父结点的数据都出现在子结点中,是子结点的最大或最小元素

image-20201008223152546

如查找元素3,B+Tree,因为没有非叶子结点没有存储数据,所以同样大小的磁盘页可以容纳更多的索引。


与B-Tree的比较

  1. 存储结构不一样,单一节点存储更多的元素,使得查询的IO次数更少
  2. 查找方式一致,所有查询都要查找到叶子节点,查询性能稳定
  3. 所有叶子节点形成有序链表,便于范围查询

数据库中的B+Tree索引可以分为聚集索引(clustered index)和辅助索引(secondary index)。上面的B+Tree示例图在数据库中的实现即为聚集索引,聚集索引的B+Tree中的叶子节点存放的是整张表的行记录数据

辅助索引与聚集索引的区别在于辅助索引的叶子节点并不包含行记录的全部数据,而是存储相应行数据的聚集索引键,即主键。当通过辅助索引来查询数据时,InnoDB存储引擎会遍历辅助索引找到主键,然后再通过主键在聚集索引中找到完整的行记录数据。

总结:

B+Tree就是,将原先每一个非叶子结点存储的key,value这种结构,改为只存储key,然后叶子结点存储key,value,通过使用链接结构,上一个指针指向上一个值,下一个指针指向下一个值这种方式。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值