mysql 为什么用B+树做索引

回答这个问题,我们要先围绕着几种树形的数据结构来判断一下优劣
二叉树:每个节点最多有两个子节点,每个子节点之间是无序的,如果要查某个数据很有可能要遍历整个二叉树,效率慢
二叉搜索树:每个节点都有如下的性质
若它的左子树不空,则左子树上所有的节点的值均小于它的根节点的值
若它的右子树不空,则右子树上所有的结点的值均大于它的根结点的值
它的左,右子树也分别为二叉树
它的时间复杂度是O(log n),每次都折一半
二叉搜索树的缺点是它不能保持平衡,因此如果极端情况下按照顺序插入拿这可二叉搜索树就会变成线性结构,时间复杂度也会是O(n),效率慢
平衡二叉树:所有节点的左右子树的高度差小于1的二叉树,它可以保持平衡 所以它的时间复杂度是O(log n)
缺点:平衡二叉树为了保持平衡,所以它会不停的进行调整,因此它进行调节平衡的性能损耗比较大
2-3-4树:每个节点中存储多个数据,可以存储1个数据,也可以存储2个数据,还可以存储3个数据,这样一来就能把一颗树的高度压的很低,查询就不会查的很深
2-3-4树的缺点:根据JAVA面向对象的特性:2-3-4树中有2节点,3节点,4节点不同的对象,基本特性相同,复用度较低,实现较为复杂,每次遍历,你不知道他这个节点里面到底有几个数据
红黑树:等价于2-3-4树,因为2-3-4树实现比较复杂,所以根据2-3-4树的特性创建了红黑树,通过着色的方式,来实现。
红黑树的缺点:结点有不同颜色,红黑树有更多的约束,红黑树需要不停的旋转,代码复杂度高。

平衡二叉树,2-3-4树,红黑树都是平衡的,为什么不能用来做innoDB的索引呢?
索引是存在于索引文件中,是存在于磁盘中的,索引通常是很大的,因此无法一次将全部索引加载到内存当中,每次只能从磁盘中读取一个磁盘页的数据到内存中,磁盘的读取速度较内存中的读取速度而言是差了好几个级别的

逻辑结构上相近的节点在物理结构上很可能会差很远,就是虽然我们存储的时候,存储的数据是连续的,但是再数据库中存储的却不是连续在一块的。每次读取的磁盘页的数据中有许多是用不上的,查找过程中要进行许多次的磁盘读取操作,适合作为索引的结构应该是尽可能少的执行磁盘IO操作,平衡二叉树没能充分利用磁盘预读功能,因此以上这些平衡的二叉树并不适合作为索引结构

B树:B树是为了充分利用磁盘预读功能而创建的一种数据结构,它是为了索引而诞生的。
特点:每个节点最多有m-1个关键字(可以存有的键值对),根节点最少可以只有1个关键字,非根节点至少要有m/2个关键字,每个根节点中的关键字都按照从小到大的顺序排列,每个关键字的左子树中的所有元素都小于它,右子树的元素都大于它,所有叶子节点都位于同一层,或者说根节点到每个叶子节点的长度都相同,每个节点都存有索引和数据,也就是对应的key和value,根节点的关键字数量范围:1<=k<=m-1,非根节点的关键字数量范围:m/2<=k<=m-1
局部性原理与磁盘预读
由于存储介质的特性,磁盘本身读取就比主存慢很多,再加上机械运动耗费,磁盘的存取速度往往是主存的几百分之一,因此为了提高效率要尽量减少磁盘I/O。为了达到这个目的,磁盘往往不是严格按需读取,而是每次都会预读。即使需要一个字节,磁盘也会从这个位置开始,顺序向后读取一定长度的数据放入内存,这样做的理论依据是计算机科学中的著名的 局部性原理

  • 当一个数被用到的时候,其周围的数据也通常会被马上使用。
  • 程序运行期间其所需的数据通常比较集中
  • 因为磁盘顺序读取的效率很高,因此对于局部性的程序来说,预读可以提高I/O效率
  • 磁盘预读是具体实现,其理论性依据是局部性原理
  • 红黑树这种结构,树的高度较大,由于逻辑上很近的节点,物理上可能很远,无法利用局部性,因此红黑树的特性明显比B-Tree差很多

B树的每个节点可以存储多个关键字,它将节点大小设置为磁盘页的大小,充分利用了磁盘预读的功能,每次读取磁盘页时就会读取一整个节点,也正因每个节点存储这非常多个关键字,树的深度就会非常小,进而要执行的磁盘读取操作次数就会非常少,更多的是在内存中对读取进来的数据进行查找。

B树的查询,主要发生在内存中,而平衡二叉树的查询,则是发生在磁盘读取中,因此虽然B树的查询次数不比平衡二叉树的次数少,但是相比起磁盘IO速度,内存中的比较耗时就可以忽略不计了,因此,B树更适合作为索引。

B+树:比B树更适合作为索引的结构是B+树,MySQL也是使用B+树作为索引的,它是B树的变种,因此是基于B树来改进的,为什么B+树会比B树更加优秀呢?
看他们的数据组成结构
B树:有序数组+平衡多叉树
B+树:有序数组链表+平衡多叉树

B树与B+树的不同之处
1.B+树非叶子节点不存放数据,只存放keys
2.B+树的叶子节点之间存在指针相连,而且是单链表
列举一个例子:查找Key的范围在3-7之间的所有的关键字
B树的表现:找到第一个符合条件的数字3后,读取这个块的内容,继续遍历B树,获得其他块的数据。
B+树的表现: 由于叶子节点有指向下一个节点的指针,因此从块1到块2的访问,通过块1指向块2的指针即可,从块2到块3也是通过一个指针即可,无需频繁的遍历B树

数据索引采用B+树的主要原因是:

  • B树在提高磁盘IO性能的同时并没有解决元素遍历的效率低下的问题。正是为了解决这个问题,B+树应运而生
  • B+树只要遍历叶子节点就可以实现整棵树的遍历,而且在数据库中通过范围查询是非常的频繁的,而B树这样操作效率比较低下

在数据库中基于范围的查询是非常频繁的,因此Mysql最终选择的索引是B+树
Mysql除了使用B+树的索引外,还使用了哈希索引

  • Hash索引是基于哈希表实现的,只有精确查询所有列的查询才有效
  • 只有Memory存储引擎支持哈希索引,是Memory表的默认索引类型,Memory表也可以使用B-Tree索引 -索引只包含HashCode和索引指针
  • 不能使用Hash索引来排序
  • Hash索引不支持键的部分匹配,因为是通过整个索引值来计算Hash值的
  • Hash索引只支持等值比较,列如使用=,In() 和 <=,>= 对于where id>100并不能加速查询
  • 访问Hash索引的速度非常快,除非有很多的hash冲突(不同的索引列值有相同的hash值),当出现hash冲突的时候,存储引擎必须遍历链表中所有的行指针,逐行进行比较,直到找到符合条件的行,
  • 如果hash冲突很多的话,一些索引维护操作的代价也会很高,当从表中删除一行时,存储引擎要遍历对应哈希值的链表中的每一行,找到并删除对应的引用,冲突越多,代价越大

全文索引
全文索引是MyISAM的一个特殊索引类型,它查找的是文本中的关键词,主要用于全文检索,在程序开发过程中,一般使用ElasticSearch作为搜索引擎,而不是Mysql

引起索引失效的原因

  1. 查询条件中的索引列使用 is null ,不会走索引
  2. 如果条件中有 or ,且部分条件不是索引列,不会走索引
  3. 多列组合索引,不满足最左原则,不会走索引
  4. like查询以%开头的列,不会走索引
  5. 如果列类型是字符串,如果在条件中数据未使用引号引用起来,则不会走索引
  6. 如果数据库引擎估计使用全表扫描比使用索引快,不会走索引
  7. 如果查询语句使用不等于 查询条件, 不会走索引
  8. 对索引字段进行计算操作,字段上使用函数,不会走索引
  9. 尽量使用覆盖索引(只访问索引的查询(索引列与查询列一致)),减少select *
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值