John的博客

学无止境

探索B树/B+树与MySQL数据库索引的关系

本文主要讲述主轴线:

  1. 由搜索/查找联系到数据结构(搜索树,红黑书,B/B+树);
  2. 进行B/B+/RBtree的性能分析;
  3. 讲述一些关于数据从内存以及磁盘读取数据的数据存储管理的内容;
  4. 对数据库引擎MyISAM和InnoDB的分析;

前言

:目前大部分数据库系统及文件系统都采用B-Tree或其变种B+Tree作为索引结构,最近学习了数据结构树这一部分的内容,又阅读了前辈们关于这一话题的的总结后,斗胆运用所学知识进行一次分析,可能比较浅薄,有不足的地方,希望可以指出;

  希望看这篇文章的你有一定的数据结构基础,因为其中很多东西,都只是提一下,帮助回忆,并不做更深的讨论,正如文中所说的,那只是沿途的风景!   

<一>搜索和查找

在学习基本语言的时候,我们知道有顺序查找和二分查找等一系列查找算法,接触数据结构之后,我们知道了二分查找的扩展,搜索树(BSTree),同时也了解到了顺序查找的弊端:面对海量数据的疲软(0(N)的时间复杂度;

而越来越多的关于搜索的数据结构也随之而来,其实最熟悉的无外乎两种,哈希查找和搜索树;

哈希查找,简单的就是直接定址了,通俗点说就是直接根据下标找到对应数据,这样的时间复杂度是O(1),当然哈希表可不止这么简单;经常利用哈希桶的方法解决大数据处理的问题,同样,哈希索引也是数据库索引的一种,本文主要介绍的还是BTree索引,关于哈希索引只是提一下,想要了解的同学,可以看下面这篇推荐的文章:http://blog.jobbole.com/100349/

搜索树,就是二分查找树,也叫二叉排序树,利用二分查找的思想构建的数据结构,它的时间复杂度和二分查找的时间复杂度一样(log2N);如果你忘记了什么是搜索树可以看下面的文章回忆一下,要不然,很难继续!
http://blog.csdn.net/bitboss/article/details/52869078

当然,搜索树还有很多变种,例如AVLTree(高度平衡二叉树)/RBTree(红黑树)/B-树/B+树/B*树;为什么说是变种,因为本质上都是搜索树,只是增加了一些不一样的特性;
为什么要增加这些特性?
当然是为了提高效率,因为随着树的高度h越大,树的效率也就会变的越低,当然,如果树的最坏情况,就是变成一种线性结构,这直接让树失去了原本的意义;
这里写图片描述

为了避免这种情况,尽量减小树的高度,于是有了AVL树,就是高度平衡二叉树;这里把AVLTree的概念列出来,方便你回忆一下,不会细说,因为这不是重点,这是旅途中的风景;

AVLTree
在计算机科学中,AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。

—这样的平衡可以降低树的高度并且提高查找的效率是毋庸置疑的;

同时还有与AVLTree不分上下的RBTree红黑树也可以达到这个效果;(其实总的来说红黑树还是要略胜AVL树)
相关博文:http://blog.csdn.net/bitboss/article/details/52983757

其实红黑树也可以作为索引的,但是出于某种原因,最终还是没有选择它,某种原因肯定是效率的问题了,没有选择它,肯定是有比它更优秀的选择嘛! 感觉我在这跟自己废话了半天

所谓没有最好只有更好,那么比RBTree更好的选择是什么呢?

B树
B-tree(多路搜索树,并不是二叉的)是一种常见的数据结构。使用B-tree结构可以显著减少定位记录时所经历的中间过程,从而加快存取速度。按照翻译,B 通常认为是Balance的简称。这个数据结构一般用于数据库的索引,综合效率较高。

B树的特征:
1. 根节点至少有两个孩子
2. 每个非根节点有[ ,M]个孩;
3. 每个非根节点有[ -1,M-1]个关键字,并且以升序排列
4. key[i]和key[i+1]之间的孩子节点的值介于key[i]、key[i+1]之间
5. 所有的叶子节点都在同一层

例如下图就是一棵B树:
这里写图片描述

B树的优势在于多路查找,这便是优于红黑树的具体原因,我没有具体的公式在这列出来,但是,想一想,我每个结点有多个key,而红黑树每个结点有一个key,那么随着数据的不断增多,红黑树的高度不断增加,效率不断降低,而B树的高度一般都很低,为甚?我一个结点放上1024个key,满了才分裂一次!

说到这里就不得不提B树的分裂;B树为甚会分裂? 因为随着数据的增多,一个结点的key满了,为了保持B树的特性,就会产生分裂,就向红黑树和AVL树为了保持树的性质需要进行旋转一样!

正如前言所说的,这里不会对树的那些具体性质进行详细的说明,因为那样有些累,所以,为什么叫探索B树/B+树与MySQL数据库索引的关系,前提是你已经直到什么是B/B+树才有资格去更深的探索!

B+树

B-Tree有许多变种,其中最常见的是B+Tree,例如MySQL就普遍使用B+Tree实现其索引结构。

与B-Tree相比,B+Tree有以下不同点:

每个节点的指针上限为2d而不是2d+1。

内节点不存储data,只存储key;叶子节点不存储指针。

例如下图就是一棵B+树:
这里写图片描述

所有的key都会在叶子结点命中,我觉得这是B+树的最大的特点,当然,请记住这一特点,因为在后面的时候会用到;

细心的你发现,在叶子结点之间有一个指针相互连接,在现在的数据库中几乎都是这样设计的B+树,因为这样可以方便遍历;

而B+树相对于B树的话更容易确定一个区间的值,如果你了解B+树的性质的话会很快明白这一特性的;

下面是参考图:
这里写图片描述
这里写图片描述


<二>内存和磁盘读取数据

学过计算机组成原理的同学对这个应该很了解!

我们为什么要介绍数据的读取呢?
因为数据库的大部分数据都是存在磁盘上面的;

一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。这样的话,索引查找过程中就要产生磁盘I/O消耗,相对于内存存取,I/O存取的消耗要高几个数量级,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘I/O操作次数的渐进复杂度。换句话说,索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数。

说点题外话,正如我前面有篇博客介绍过的,关于大数据的处理,都是利用我们现在所学的数据结构,有兴趣的同学可以了解一下:
http://blog.csdn.net/bitboss/article/details/53140148

关于数据从主存和磁盘读取的说明,我也只能说一个大概,细致点的估计也不行,主要让大家有个了解;

首先,我们的主存在我们的内存中是以二维矩阵的形式存放的,就像一个正在被检阅的方队,如下图所示(6*6):我们通过行地址和列地址获取该块内存的数据;这个操作就是读操作;

这里写图片描述

我这画图功底真是有够搓;

而从内存中的读取是非常快的,内存中的一块,一般是一页,大约是4k,方便对内存进行分配;而如果要读取的数据不在主存的话,会抛出一个缺页中断,去磁盘读取数据;(又忍不住说点题外话,主存是RAM,而现在我们一般用的磁盘都是机械盘,即访问速度很慢,主要存储介质是带磁的介质。利用磁性产生信号对应0,1信号,才达到存储信息的目的;而现在的固态硬盘则是以DRAM或者闪存为存储介质的,读取速度特别快,但是价格高,而且不易恢复数据);

下面说说磁盘的物理构造:
这里写图片描述

这里写图片描述

就和小时候的碟片一样,从圆心开始,有一圈一圈的同心圆扩散开来,哪些相邻的的同心圆所形成的夹缝就是磁道,更形象点的就是80年代的留声机,但是又把磁盘划分成一个一个扇形区域,这些扇形区域就是最小的存储单元,当需要从磁盘读取数据时,系统会将数据逻辑地址传给磁盘,磁盘的控制电路按照寻址逻辑将逻辑地址翻译成物理地址,即确定要读的数据在哪个磁道,哪个扇区。为了读取这个扇区的数据,需要将磁头放到这个扇区上方,为了实现这一点,磁头需要移动对准相应磁道,这个过程叫做寻道,所耗费时间叫做寻道时间,然后磁盘旋转将目标扇区旋转到磁头下,这个过程耗费的时间叫做旋转时间。

又说点题外话,磁盘上的顺序读取一般比较快,所以一般一次读取一段长度的数据,称为预读,因为一般一个数据被读取,它旁边的数据一般也会被用到,这叫局部性原理


<三>MyISAM和InnoDB

MyISAM 和 InnoDB 是MySQL的两代搜索引擎;
区别在于,对于辅助索引的实现原理不一样,并且MyISAM是索引和文件分离的,而InnoDB不是;

一般以主键为索引的叫做主索引,而以其他键为索引的叫做辅助索引;

直接上MyISAM的实现原理,利用B+树实现,
这里写图片描述

由上图可以看出,col1是主键,而叶子结点存储的数据是一个地址,通过地址找到数据;

下面是辅助索引(和主索引不同的是辅助索引的key是可以重复的)
这里写图片描述

仔细对照MyISAM的这两张图,看看有什么主索引和辅助索引有什么区别?

下面看看InnoDB B+树实现

这里写图片描述

这是主索引,即利用主键构造的B+树;

注意,和MyISAM不同的是叶子结点的数据域保存的是全部数据;

下面在看辅助索引:

这里写图片描述

仔细看辅助索引和主索引的区别,辅助索引的叶子结点保存的是主键;这就是MyISAM和InnoDB最大的不同;

既然MyISAM和InnoDB是MySQL的两代引擎,肯定会有一个提升,而InnoDB是最新一代,那么它到底优在哪里?

试想,MyISAM和InnoDB都是以B+树为基础实现的,相对于B树的不同其实前面已经讲过,即数据域和结点分离;

而MyISAM更是索引和文件分离,B+树的叶子结点的数据域存放的是文件内容的地址,主索引和辅助索引的B+树都是如此,那么如果我改变了一个地址,是不是所有的索引树都得改变,正如前面我们讲的在磁盘上频繁的读写操作是效率很低的,而这块又不适用局部原理,因为逻辑上相邻的结点,物理上不一定相邻,那么这样就会造成效率上的降低;

于是乎,InnoDB就产生了,它让除了主索引以外的辅助索引的叶子结点的数据域都保存主键,先通过辅助索引找到主键,然后通过主键找到叶子结点的所有数据,听起来貌似很麻烦,遍历了两棵树,但是,这样如果有了修改的话,改变的只是主索引,其它辅助缩印都不用动,而且,数据库中的树的每一个结点的key可不是咱们给的那么少,试想如果一个结点有1024个key,那么高度为2的B+树都有1024*1024个key,所以一般树的高度都很低,所以,遍历树的消耗几乎忽略不计!

文章到这里就到了一个结尾,真的写的很累,其中有不完善的地方,以后会逐步完善;

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/bitboss/article/details/53219945
个人分类: 数据结构
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭