索引数据结构

        常用的数据结构:Hash表,二叉树,平衡二叉查找树(红黑树是一个近似平衡二叉树),B树,B+树。数据结构示例可参考:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

        Hash表

        Hash表以键值对的方式存储数据,类似JAVA中的Map。Key存储索引列,Value存储行记录或者行磁盘地址。Hash表在等值查询时效率 很高,时间复杂度为O(1);但是不支持范围快速查找,范围查找时还是只能通过扫描全表方式。

        二叉树

        二叉树特点:每个节点最多有2个分叉,左子树和右子树数据顺序左小右大。如:

         在检索28时,只需要3次IO就可以检索出来。这样的数据结构貌似效率不错,但到二叉树的检索复杂度和树高相关。且并不是任何列使用二叉树都会提升效率,如:自增主键

 平衡二叉查找树

        平衡二叉树是采用二分法思维,平衡二叉查找树除了具备二叉树的特点,最主要的特征是树的左右两个 子树的层级最多相差1。在插入删除数据时通过左旋/右旋操作保持二叉树的平衡,不会出现左子树很 高、右子树很矮的情况。

        使用平衡二叉查找树查询的性能接近于二分查找法,时间复杂度是 O(log2n)。查询id=6,只需要两次 IO。

平衡二叉树存在的问题

        1. 时间复杂度和树高相关。树有多高就需要检索多少次,每个节点的读取,都对应一次磁盘 IO 操 作。树的高度就等于每次查询数据时磁盘 IO 操作的次数。磁盘每次寻道时间为10ms,在表数据 量大时,查询性能就会很差。(1百万的数据量,log2n约等于20次磁盘IO,时间20*10=0.2s)

        2. 平衡二叉树不支持范围查询快速查找,范围查询时需要从根节点多次遍历,查询效率不高。

B

        访问二叉树的每个节点就会发生一 次IO,如果想要减少磁盘IO操作,就需要尽量降低树的高度。

        InnoDB存储引擎一次IO会读出一页16K的数据。假如key为bigint=8字节,每个节点有两个指针,每个指针为4个字节,一个节点占用的空间16个字节(8+4*2=16)。那么二叉树一次IO有效数据量只有16字节,空间利用率极低。

        为了最大化利用一次IO空间,一个朴素的想法是在每个节点存储多个元素,在每个节点尽可能多的存储 数据。每个节点可以存储1000个索引(16k/16=1000),这样就将二叉树改造成了多叉树,通过增加 树的叉树,将树从高瘦变为矮胖。构建1百万条数据,树的高度只需要2层就可以(1000*1000=1百 万),也就是说只需要2次磁盘IO就可以查询到数据。磁盘IO次数变少了,查询数据的效率也就提高 了。

        这种数据结构我们称为B树,B树是一种多叉平衡查找树,如下图主要特点:

        1. B树的节点中存储着多个元素,每个内节点有多个分叉。

        2. 节点中的元素包含键值和数据,节点中的键值从大到小排列。也就是说,在所有的节点都储存数据。

        3. 父节点当中的元素不会出现在子节点中。

        4. 所有的叶子结点都位于同一层,叶节点具有相同的深度,叶节点之间没有指针连接。

        对于一个主键索引,主键值bigint=8字节,data为记录的磁盘地址为4个字节,一个元素占用空间12字节。

        一个磁盘块大小为16k。磁盘块中的分叉数=元素树+1,假设可以存储x个元素,12x+(x+1)*4=16k,约等于 1000,也就是说一页中可以最多可以存储1000个元素。

        (1)二层B树结构可以存储的数量1000*1000=1百万,三层树结构可以存储的数量1000*1000*1000=1百 亿。

        (2)B树的高度一般都是在2-4这个高度,树的高度直接决定IO读写的次数以及查询时间复杂度 (O(log2n))。

以下面的B树为例,我们的键值为表主键,具备唯一性。

        

下面我们看一下,如何使用B树查询数据:

        假如我们查询值等于15的数据。查询路径磁盘块1->磁盘块2->磁盘块7。

        第一次磁盘IO:将磁盘块1加载到内存中,在内存中从头遍历比较,15<17,走左路,到磁盘寻址 磁盘块2。

        第二次磁盘IO:将磁盘块2加载到内存中,在内存中从头遍历比较,12<15,到磁盘中寻址定位到 磁盘块7。

        第三次磁盘IO:将磁盘块7加载到内存中,在内存中从头遍历比较,15=15,找到15,取出data, 如果data存储的行记录,取出data,查询结束。如果存储的是磁盘地址,还需要根据磁盘地址到磁盘中 取出数据,查询终止。

        相比二叉平衡查找树,在整个查找过程中,虽然数据的比较次数并没有明显减少,但是磁盘IO次数会大大减少。同时,由于我们的比较是在内存中进行的,比较的耗时可以忽略不计。B树的高度一般2至 3层就能满足大部分的应用场景,所以使用B树构建索引可以很好的提升查询的效率。

B树的缺点

        1. B树不支持范围查询的快速查找,如果我们想要查找15和26之间的数据,查找到15之后,需要回 到根节点重新遍历查找,需要从根节点进行多次遍历,查询效率有待提高。

        2. 如果data存储的是行记录,行的大小随着列数的增多,所占空间会变大。这时,一个页中

可存储的数据量就会变少,树相应就会变高,磁盘IO次数就会变大。

B+

        在B树基础上,MySQL在B树的基础上继续改造,使用B+树构建索引。B+树和B树最主要的区别在于非叶子节点是否存储数据的问题。

- B树:非叶子节点和叶子节点都会存储数据。

- B+树:只有叶子节点才会存储数据,非叶子节点只存储键值。叶子节点之间使用双向指针连接,最底层的叶子节点形成了一个双向有序链表。

如何使用B+树如何查询数据:

等值查询

        假如我们查询值等于15的数据。查询路径磁盘块1->磁盘块2->磁盘块5。

        第一次磁盘IO:将磁盘块1加载到内存中,在内存中从头遍历比较,15<28,走左路,到磁盘寻址 磁盘块2。

        第二次磁盘IO:将磁盘块2加载到内存中,在内存中从头遍历比较,10<15<17,到磁盘中寻址定位 到磁盘块5。

        第三次磁盘IO:将磁盘块5加载到内存中,在内存中从头遍历比较,15=15,找到15,取出data, 如果data存储的行记录,取出data,查询结束。如果存储的是磁盘地址,还需要根据磁盘地址到磁盘中 取出数据,查询终止。

范围查询

        假如我们想要查找15和26之间的数据。查找路径是磁盘块1->磁盘块2->磁盘块5。

        1.首先查找值等于15的数据,将值等于15的数据缓存到结果集。这一步和前面等值查询流程一样,发 生了三次磁盘IO。查找到15之后,底层的叶子节点是一个有序列表,我们从磁盘块5,键值15开始向后遍历筛选所有 符合筛选条件的数据。

        2.第四次磁盘IO:根据磁盘5后继指针到磁盘中寻址定位到磁盘块6,将磁盘6加载到内存中,在内存 中从头遍历比较,15<17<26,15<26<=26,将data缓存到结果集。

        3. 主键具备唯一性(后面不会有<=26的数据),不需再向后查找,查询终止。将结果集返回给用 户。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值