B+树 —— 数据库的灵魂

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: B+树 —— 数据库的灵魂

背景

虽然 Nosql 风生水起,关系型数据库在当前的开发中仍然扮演着不可或缺的角色。因此在面试中也会被时常问到,很多问题即使是工作多年的同学仍然会磨棱两可,例如:

  1. 为什么使用B+树,而不是B树作为底层数据结构?
  2. 最左前缀匹配原则 为什么跟索引中字段顺序相关,而与查询中字段顺序无关?
  3. Like 查询能够使用索引吗?
  4. 主键为什么最好选择递增的字段?

很多人把原因归结于没有认真准备。靠记忆死记硬背终归落了下乘,归根结底还是没有把握住本质。MySQL的本质是什么?当然是其存储引擎。要想对数据库有本质的认识,了解存储引擎底层的数据结构 B+树 是一堂必修课。

B+ 树

定义

如果此B+树的阶数是 m+1,则:

  • 每个节点最多有 m 个 Key 及 m+1 个子节点
  • 除根节点外,所有节点必须半满(Half-full)
  • 如果 m 是 偶数,且 m = 2d
  • 叶节点半满:至少有 d 个Key
  • 非叶节点半满:至少有 d 个Key
  • 如果 m 是奇数,且 m = 2d+1
  • 叶节点半满:至少有 d+1 个 Key
  • 非叶节点半满:至少有 d 个Key

算法

查找

从根节点开始,检查非叶子节点的索引项,可以使用二分(或线性)搜索进行查找,以找到对应的子节点。沿着树向下遍历,直到到达叶节点

根据以上方法查找 15*,可知它不在该树上

插入
  1. 首先,查找要插入的 叶节点 L
  2. 接着把数据项插入这个节点中
  • 如果没有节点处于违规状态,则处理结束
  • 否则,均匀的拆分 L 为两个节点( L和 新节点 L2),使得每个都有最小数目的元素
  • 将索引项中间的 key 复制到父节点(Copy up)
  • 将指向 L2 的索引项插入到 L 的父节点
  1. 沿树递归向上,继续这个处理直到到达根节点
  • 若要拆分索引节点,需均匀地拆分索引条目,将中间的 key 移动到父节点(Push up)

与叶节点拆分对比操作不同

  1. 如果根节点被分裂,则创建一个新根节点。

假设,将 8* 插入到上述 B+ 树,观察在叶节点和非叶节点拆分中如何保证半满的。并注意 Copy up 和 Push up 之间的区别,确保理解其中的原因。

a) 首先找到的 叶节点 L,并拆分

  • 将 索引项的 key 5 Copy up
  • 将 指向 L2 的 索引项指针添加到 L 的 父节点

b) key 5 Copy up 到父节点子后,导致非叶节点拆分:

  • 17 Push up 到 父节点

c)最终根节点被拆分,并导致树高度增加,得到以下B+树

删除
  1. 从根节点开始,查找该项归属的 叶节点 L
  2. 删除该项
  • 如果叶节点L 多于半满,则处理结束
  • 如果叶节点L 不足半满的索引项
  • 尝试从兄弟节点(与L具有相同父级的相邻节点)借索引项,重新分配。
  • 如果重新分配失败,则合并 L 和 兄弟节点
  1. 如果发生合并,则必须从L的父索引项中删除索引项(指向L或兄弟节点的)
  2. 递归此处理直到节点是合法状态,或者到达根节点。

假设,对上述B+树,依次删除 19*、20*、24*

a) 删除 19*,较为简单,得到

b) 删除 20*,是通过重新分配完成的。注意中间的 key 是如何 Copy up 的

c) 删除 24*,导致与右侧索引项的合并。

然后,沿树向上,父节点同样需要与左侧兄弟节点合并,导致根节点的 “pull down”

复合索引

复合索引的B+树上的键值,就像单key的索引一样。和按字母顺序排列一个句子一样,复合索引中各个字段的顺序很重要。例如,下图为复合索引 (branch_name, balance) 的 B+树

  1. 例如,(Bournemouth, 1000) 小于等于 (Bournemouth, 1000) ,因此它出现在第一个叶节点中; (Bournemouth, 7500) 大于 (Bournemouth, 1000) ,因此它出现在第二个叶节上
  2. 例如,尽管 (Armagh, 1500) 第二个字段的值大于(Bournemouth, 1000)对应字段的值。字段的顺序意味着 (Bournemouth, 1000) 小于 (Bournemouth, 1000)

因此,上面的B+树可以用来搜索 (branch_name) 或 (branch_name, balance) ,而不能搜索 (balance)。例如,balance=2000 出现在B+树的两个路径中。

聚簇索引

由B+树的结构可知,数据记录本身被存于叶子节点上。就要求同一个叶子节点内(大小为一个内存页或磁盘页)的各条数据记录按主键顺序存放,因此每当有一条新的记录插入时,B+树会根据其主键将其插入适当的节点和位置

  1. 如果使用递增的字段作为主键,新增记录就会添加到当前索引节点的后面。不需要因为插入移动已有数据,因此写入效率很高
  2. 如果使用随机的字段作为主键,新增记录需要插入到索引的中间位置 。为了将新记录插到合适位置而移动已经存在的数据。同时频繁的移动、分页操作造成了大量的碎片,降低磁盘读写速度

总结

  1. 为什么使用B+树,而不是B树作为底层数据结构?
  1. 树高较低,磁盘IO次数少
  2. 有利于范围、排序、分组等查询
  1. 最左前缀匹配原则 为什么跟索引中字段顺序相关,而与查询中字段顺序无关?
  1. 因为索引中字段的顺序决定了建立一颗怎样的索引树
  2. 能否使用索引的本质在于,查询语句能否沿树游走
  1. like 查询能够使用索引吗?
  1. 问题2
  2. % 开头的like语句无法沿树游走,因此无法使用索引
  1. 主键为什么最好选择递增的字段?

详见:聚簇索引

很多的知识都是串起来的,摸清了B+树,那么对于MySQL的 Explain工具 也就自然能够做到胸有成竹,基本的索引优化自然也就手到擒来。

参考

  1. https://web.stanford.edu/class/cs346/2015/
  2. https://pdfs.semanticscholar.org/0d7b/8b9172a69fa069c9c38b5f01bd37a498563c.pdf

本文作者 : cyningsun

本文地址https://www.cyningsun.com/08-25-2020/mysql-bplustree.html

版权声明 :本博客所有文章除特别声明外,均采用 CC BY-NC-ND 3.0 CN 许可协议。转载请注明出处!

# 数据库

  1. 深入理解 Redis cluster GOSSIP 协议
  2. 如何配置 go-redis 连接池
  3. 如何使用 Redis 存储对象
  4. Redis cluster 细节与技术选型
  5. etcd 实现与选型分析
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
10月前
|
存储 关系型数据库 MySQL
【MySQL 解析】数据库为什么使用B+树而不是B树
【1月更文挑战第11天】【MySQL 解析】数据库为什么使用B+树而不是B树
|
10月前
|
存储 关系型数据库 MySQL
【MySQL】数据库中为什么使用B+树不用B树
【MySQL】数据库中为什么使用B+树不用B树
|
存储 Oracle 关系型数据库
数据库的存储结构
数据库的存储结构
427 0
数据库的存储结构
|
存储 数据库 索引
【数据库视频】对索引的了解
【数据库视频】对索引的了解
|
SQL 缓存 关系型数据库
数据库查找及其优化
所采用的查询语句完全一致。不仅包括查询的字段,也包括查询的条件。如果用户查询一个产品信息表,使用了查询条件,只查询最近一个月新建的产品信息。显然此时查询的结果是查询的子集,应该可以使用数据管理。数据库仍然会先重新解析SQL语句,然后从硬盘上的数据文件中去获取数据
95 0
|
存储 SQL 安全
数据库的视图与索引经典题
数据库的视图与索引经典题
274 0
|
存储 算法 数据库
【数据库系列】存储引擎(二)B树概述
注:在本文中“结点”和“节点”同义,在B树部分,“节点”和“页”同义。 背景知识 很多数据库都是基于B树 传统树的特点回顾 由数据结构与算法的知识可知,BST(二叉搜索树)的左子树的值<根值<右子树的值。
135 0
|
存储 SQL 关系型数据库
数据库杂谈(七)—— 数据库的存储结构
本文主要讲述了数据库的存储结构
388 0
|
存储 SQL 关系型数据库
MySQL:如何将树形结构存储在数据库中
怎么存储这个结构?并且要获取以下信息: 1.查询小天的直接上司; 2.查询老宋管理下的直属员工; 3.查询小天的所有上司; 4.查询老王管理的所有员工。
1593 1
MySQL:如何将树形结构存储在数据库中
|
SQL 自然语言处理 关系型数据库
15_ 数据库 _ 索引
15_ 数据库 _ 索引
145 0