要说mysql为什么要用B+树做索引,我们先看看如果用其他数据结构做索引会怎样,做个对比
一 hash表
1需要占用大量内存空间,每次使用hash表需要将数据全量加载到内存,比较浪费内存空间,所以mysql的memory存储引擎中使用了hash索引,innodb存储引擎支持自适应hash,由mysql自己控制,不是人为控制
2 每次都是等值查询,根据key计算出hash值,定位到某一位置进行key比较,无法解决排序,范围查询等问题
3 hash表的时间复杂度是O(1),如果只知道数据或者数据中的部分内容,想在数组中找到这个数据,还是需要遍历数组,时间复杂度会退化为O(n)或者极端情况下所有 Key 的数组下标都冲突,那么hash表就退化为一条链表时间复杂度会退化为O(n)。hash算法不够优秀也会导致数据散列不均匀,浪费存储空间
基于上面这些缺点,mysql中的inbodb和myisam存储引擎没有使用hash表赖存储索引数据,而memory存储引擎使用了hash表方式
二 二叉树
二叉树的特点:
1 一个节点只能有两个子节点,节点度不能超过2
2 左子节点小于本节点,右子节点大于等于本节点
二叉树可以使用二分查找的方式来进行数据检索,但是如果递增或者递减会导致退化成链表;数据量很大的时候,会导致树很高,磁盘IO就很大
二叉树最关键的原因是左右分支不够平衡,因此有了二叉平衡树,即AVL树。AVL树要求左子树跟右子树高度差不能超过1,数据插入时会造成N个旋转保证树的平衡。这样查询的效率上来了,但是新增的效率就比较低。随着数据的越来越多,树会越来越深,从而导致查询效率也变的低下
三 红黑树
红黑树是一种平衡二叉树,它继承了二叉树的优点,由解决了二叉树遇到的自增数据索引失效的问题,因为红黑树的会对树的结构进行调整,进行左旋或者右旋及颜色变换等操作,始终保证 左子节点数<父节点数<右子节点数,最长子树不超过最短子树的两倍
红黑树不作为Mysql索引的原因是,当数据量大时候,树的深度也很大,每个父节点最多只能有两个子节点,如果表中有很多数据,那么树的深度很大,达到十几或几十层,这样的深度对于Mysql的磁盘寻址非常不利,增加io的次数,相当耗时
四 B树
B树又叫二三树,每个节点可以包含多个key值,在B树有一个degree(翻译成度或者阶)的概念,每个节点中至多可以存储N-1个节点,树的深度就不会变深,查找的io次数就会减少,查询的速度就会提升
缺点:
1 每个节点都有key,同时也包含data,每个页存储空间是有限的,如果data比较大的话会导致每个节点存储的key数量变小
2 当存储数据量很大的时候会导致深度加大,增大查询磁盘io次数
五 B+树
1 B+树的关键字的搜索采用的是左闭合区间,之所以要这样是因为要最好的去支持自增的id,也是Mqsql设计的初衷,保证id=1命中的情况下,也去继续往下查找,知道找到叶子节点中1
2 B+树中的根结点和支节点中没有数据区,关键字对应的数据只保存在叶子节点中,所以只有叶子节点中的关键字数据区才会保存真正的数据内容或者数据对应的地址,但是在B树中,如果根结点命中,是直接返回的,B+树中,叶子节点不会保存子节点的引用
3 B+树的叶子节点是顺序排列的,并且相邻节点之间是顺序引用的关系,叶子节点之间通过指针相连
Mysql为什么最终选择了B+树作为索引的数据结构
1 B树能解决的问题,B+树都能解决,且能够更好的解决,降低了树的高度,增加节点的数据存储量。
2 B+树的扫库和扫表能力更强,如果根据索引去根据数据表扫描,对B树扫描,需要整颗树遍历,B+树只需要遍历所有的叶子节点
3 B+树的磁盘读写能力更强,根结点和支节点不保存数据区,所有的根结点和支节点天同样大小的情况下,保存的关键字更多,叶子结点不存子节点的引用,所以,B+树读写一次磁盘加载的关键字更多
4 B+树具有天然的排序功能
5 B+树的查询效率更加稳定,每次查询数据,查询IO次数是稳定的。