前言
在今天的互联网企业中,mysql是必须掌握的技能,可能维护mysql的技能都已经交给dba或者直接采用相关云服务,但是了解其中的原理还是很重要的。例如mysql中的存储引擎、事务管理、binlog日志、主从同步等等,这篇文章主要记录下对mysql的b+树的学习总结,如果对此概念已经比较了解,就可以不用在阅读了。
目录
- 前言
- 索引的数据结构
- hash
- b+树
- b+树原理
- 什么是二叉树?
- 什么是b树?
- b+树
- mysql表设置自增长id的作用
- 总结
- 参考
索引的数据结构
mysql的InnoDB常用的索引数据结构有2种,hash和b+树。
hash
hash就是建立hash表,根据hash算法,建立索引键和数据的映射关系,hash可能会出现冲突,解决hash冲突有几种方式:
- 开放定址法: 一旦出现冲突就向后查找空位,直到找到空位为止
- 再hash法: 采用多个hash函数,hash出现冲突,继续下一次hash
- 链表法: 出现冲突时,通过链表实现共同进入该位
- 公共溢出区: 出现冲突时,都进入公共溢出区
InnoDB中采用的hash结构是第3种。
优点
- hash算法时间复杂度低,对于等值查找效率很高(但是要求查找值重复度低,如果重复度高,进入链表查询还是需要遍历)
缺点
- 范围查找不适用
- 无法用来做数据排序,由于hash后的数据排序可能跟原有数据排序不一致
- 组合索引,部分索引无法实现查询,组合索引采用多键计算hash,但是如果只用前面几个索引查询,就无法使用
我们发现hash索引的局限性太强,很多场景无法适用,这也是我们实际使用中几乎没人使用该索引数据结构的原因。
b+树
我们在设计mysql数据库的表时,都会默认加个业务无关的自增长主键id,至于为啥这样可能很多人不理解,等会我们来解释。
b+树原理
什么是二叉树?
二叉搜索树有个特性,就是left-child小于都小于自己,right-child都大于自己,那么我们看下面这个树,右侧的树虽然也满足,但是其查找性能已经不是2分法而是线性,这种情况我们称之为失去了”平衡“。
什么是b树?
b树解决了二叉树不能平衡的问题,在b树中所有的叶子节点在同一层,有以下几个特性:
- 定义任意非叶子结点最多只有M个儿子;且M>2
- 根结点的儿子数为[2, M];
- 除根结点以外的非叶子结点的儿子数为[M/2, M];
- 每个结点存放至少M/2-1(取上整)和至多M-1个关键字;
- 非叶子结点的关键字个数=指向儿子的指针个数-1;
- 非叶子结点的关键字:K[1], K[2], …, K[M-1];且K[i] < K[i+1];
- 非叶子结点的指针:P[1], P[2], …, P[M];其中P[1]指向关键字小于K[1]的子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树;
- 所有叶子结点位于同一层;
b树如何实现平衡
由于M/2的限制,在插入结点时,如果结点已满,需要将结点分裂为两个各占M/2的结点;删除结点时,需将两个不足M/2的兄弟结点合并;
逻辑结构
特点
数据分布在所有节点中,在查找的时候一旦匹配到,就可以拿到数据。其查找的时间复杂度为: O(logN)
b+树
b+树是b树的变型,相比于b树其有以下几个不同:
- 非叶子结点的子树指针与关键字个数相同
- 为所有叶子结点增加一个链指针
- 所有关键字都在叶子结点出现
相比于b树其优点
- 非叶子节点的信息更加少,减少io开销
- 所有数据都在叶子节点,查找性能稳定
- 叶子节点之间有链表指针关联,更加利于遍历
鉴于以上的优势,b+树更适合做文件索引,这也是InnoDB采用的原因。
mysql表设置自增长id的作用
回到我们提出的问题,InnoDB的主键索引采用b+树,其非叶子节点中存储的是主键id,其叶子节点存储的是具体的行数据,这是聚簇索引,也就是主键索引。
非主键索引中区别在于,其叶子节点存储的不是实际的数据,而是主键的值。
那么如果不按照主键查找呢?
按照其他索引查找数据,其他索引的叶子节点并没有数据,其只有数据的主键,在查找到数据主键的时候,再去通过主键索引查找数据的数据返回。
为啥主键索引是自增长id呢?
在聚簇索引写入的时候,叶子节点时是通过通过链表关联的、且有序,顺序的主键会使磁盘写入变成顺序的,效率更高。 批量读取数据的时候效率也更高。
试想一下,如果id是非自增长的,那么每次无论是非叶子节点中插入数据会变成随机的而不是顺序的,效率自然变低。
总结
今天先说到这里,有错误的地方望指出,后续有空继续输出mysql其他方面的学习总结。