MySQL索引数据结构二叉树、红黑树、B-Tree、B+Tree、Hash

索引:帮助MySQL高效获取数据的有序的数据结构。

假设我们有一张表table,包含Clo1和Clo2两个字段 

内存地址Clo1Clo2
0x07136
0x5A220
0x7A380
0xF348
0x77528
0xD1666
0x89788

 在没有索引情况下的执行下面SQL

select * from table where Clo2 = 66;

过程如下:

在没有索引的情况下要找到Clo2=66的数据,要经过6次的I/O,6次RAM内存比较,在内存中比较的时间会快,完全可以忽略不计,但是6次的I/O时间会很长(导致慢SQL主要原因之一)。

通过索引进行SQL效率优化,可以认为是尽可能的减少I/O的次数,就是后面讲的降低树的高度。如何减少I/O的次数,这就涉及到了数据结构。接下来介绍一下二叉树、红黑树(二叉平衡树)、B-Tree、B+Tree、Hash的数据结构模型。

数据结构可视化学习网站: 

Data Structure Visualizationhttps://www.cs.usfca.edu/~galles/visualization/Algorithms.html

1.二叉树 

  • 右侧子元素大于父元素数据,左侧子元素小于父元素数据

下面我们通过上面学习网站看一下Clo1建立二叉树的数据结构和Clo2建立二叉树数据结构

Clo1是单边增长的列,生成的二叉树结构与链表一样,树的高度是7,Clo2生成的二叉树树的高度是3。模拟一下查询Clo1=6,Clo2=66这一条数据:

使用Clo1进行查询

 

  

找到Clo1=6的数据一共经历了6次I/O和6次比较,在树的第6层拿到数据。

使用Clo2进行查询

 找到Clo2=66的数据,进行了3次I/O和比较,在树的第3层拿到数据

由已上例子可以看出进行的IO次数就是数据所在树的层数

2.红黑树(二叉平衡树)

红黑树的结构与二叉树结构一样,区别在于生成的过程中红黑树会自动平衡节点

再模拟一次查询Clo1=6的数据:经历了3次I/O和比较,在树的第3层拿到数据。同样的使用Clo=6查找数据,二叉树用了6次I/O,红黑树用了3次I/O,由此可看出红黑树要比二叉树更适合创建索引。但是数据量大了,到了几百万的时候树的高度依然不可控。

红黑树的根节点只有一个数据,我们将根节点的内存扩大多存放一些数据就可以降低树的高度,接下来的B-Tree就是这种结构。

3.B-Tree

  • 叶节点具有相同的深度,叶节点的指针为空
  • 所有索引元素不重复
  • 节点中的数据索引从左到右递增排列
  • 节点中存储data数据

 当索引结构以B-Tree数据结构创建时,再次查找Clo2 = 66 的数据:

1.将树的第一层所有数据load到内存,使用比对算法(如:二分查找)进行比对

        a.如果有66则将对应的data数据从内存中读取出来

        b.如果没有,则会找66对应的区间地址(35-80)

2.将35-80这一页的所有数据再拿出来与66做比较

        a.如果有66则将对应的data数据从内存中读取出来

        b.如果没有,则会找66对应的区间地址

 以此类推,直到找到66或者这一系列的数据比对完毕

使用了B-Tree数据结构后,我们查询Clo2=66的数据只做了两次的I/O,比红黑树的效率更高一些。

但是MySQL底层用的依然不是B-Tree,而是B-Tree的变种B+Tree

4.B+Tree

  • 非叶子节点不存储data,只存储索引(冗余),目的是可以放更多的索引
  • 叶子节点包含所有索引字段
  • 叶子节点使用指针连接,提高区间访问的性能

 1.为什么非叶子节点不存储data,可以放放更多的索引,也是MySQL索引数据结构使用B+Tree不使用B-Tree的主要原因。

通过SHOW GLOBAL STATUS like 'Innodb_page_size';可以看到mysql数据库中定义文件页大小是16384B(16KB)。

如果叶子节点不存储data,假设字段类型是BigInt,字段值占用8B,地址值占用6B,一层16KB大概可以存储1170个索引值

如果叶子节点存储data,一般的data+字段值+地址值不会大于1KB,我们就按照平均1KB计算,一层16KB也就只能存储16个索引值

2.为什么MySQL页文件默认是16KB?

由问题1知道第一层一页数据可以存1170个索引值,如果再加一层,第一层的每一个地址值指向第二层的一页数据,我们就可以存储  1170X1170  个索引值,第二层每个地址值指向第三层的一页数据,第三层的叶子节点要带数据存储每一页只存16个数据,三层高的树可以存储  1170 X 1170 X 16 大约2千万左右的数据。

3.叶子节点指针的作用

B+Tree有链接指针可以快速的找下一页的数据,B-Tree没有指针,当取完当前区域的数据后,还得回到根节点(第一层)查找大于28的数据再做对应的I/O。 所以B+Tree可以通过叶子节点指针提高区间访问的性能。

MySQL优化点:将根节点(有可能是所有非叶子节点)存储到内存,减少I/O次数,只有在读取叶子节点才进行一次I/O,性能更高效了。

5.Hash

  • 对索引的key进行一次hash计算就可以定位出数据存储的位置
  • 很多时候Hash索引要比B+Tree索引更高效
  • 仅能满足“=”,“in”,不支持范围查询
  • 存在hash冲突

hash算法原理:hash计算后的数据都会进入到容器Hash桶内,桶内按照下标位置分配好了内存空间,如果通过hash()计算后得到的值为2,将该数据放到次下标对应的区域。如下图

仅通过一次hash计算就可以确定数据的存储位置,如查询李四:

① 通过hash(李四)=2

②把hash桶内的下标为2的数据load到内存,进行比较

hash仅使用了一次I/O就能拿到数据,B+Tree可能会有多次,所以一些场景hash索引会比B+Tree更高效。但是这种结构对范围查询不友好,所以MySQL底层基本用的是B+Tree。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Seventeen117

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值