摘要:介绍二叉树、AVL树、红黑树、B树、B+树和B*树等六种树的数据结构后,浅析MySQL InnoDB索引选择B+树的原因,并给出一些MySQL 索引高频面试题。
目录
- 综述
- 二叉查找树
- AVL树/红黑树
- B树(B-tree)
- B+树(B+ Tree)
- B*树(B star Tree)
- 树的总结
- 实际应用中的索引优化
- 聚集索引和辅助索引
- 面试实战指南
- 结束语
- Reference
综述
数据库是后端工程师绕不开的核心技术,而索引则是核心中的核心。在日常工作中,我们每天都在和索引打交道,索引问题也是高级工程师面试中,面试官最喜欢考察的地方。
很多开发者在面试中谈及索引时,往往只能给出一些零散、机械的记忆性答案,比如“B+树查询快”、“索引能提速”。这样的回答在面试官心中留下的深刻印象就是此候选人学习知识浅尝辄止,不够深入,不够努力。真正体现一个工程师技术深度的,是对索引背后设计原理的系统性理解,以及在复杂场景下进行选型和优化的能力。
在 MySQL 中,通常所说的索引,如果没有特别声明,默认都是指 B+ 树数据结构的索引。在介绍各种树的数据结构和MySQL索引之前,先介绍本文多次使用的几个基本概念:
节点:包含一个数据元素及若干指向子树的指针等。
根节点:是树的起始节点,它没有父节点,就像是大树的根基,其它节点都从根节点衍生出来。
叶子节点:也叫终端节点,是没有子节点的节点,它们位于树的最底层,就像树枝的末梢。
内部节点(internal Node):至少有一个子节点的节点,包括根节点和所有非叶子节点。
兄弟节点: 具有相同父节点的节点。
节点的度:该节点拥有的子节点个数。例如二叉树中节点的度最大为 2,即每个节点最多有两个子节点。
树的度:整棵树中所有节点的最大度数。
层级:从根节点开始,树的每一层都是一个层级。
高度(height):当前节点到最远叶子节点的最长路径上的节点数。
平衡因子(Balance Factor):简称BF,每个节点的左右子树的高度之差。
数据页:树上每个节点在计算机中叫做数据页,是 InnoDB 存储引擎与磁盘交互的最小单位,默认大小为 16KB。
阶数:一个节点最多可以有多少个子节点(即节点的最大度数),一般用小写字母m表示阶数。用⌈m/2⌉表示对m/2向上取整数。例如,三阶 B+ 树 → 每个节点最多 3 个子节点 → 最大度 = 3。
在数据库中我们将B+树作为索引结构,可以加快查询速度,此时树中的key一般是表的主键。例如,MySQL InnoDB 的记录,就是按照主键由小到大排序后,存在 B+ 树的叶子节点里。树中每个节点存储了关键字(key)、关键字对应的数据(data)以及指向孩子节点的指针。我们将一个key及其对应的data称为一条 记录。但为了方便描述,除非特别说明,后续文中就用“关键字”来代指(key, value)键值对。下面就是MySQL中索引的数据结构:
图1 索引的数据结构。备注:磁盘块4有笔误,应该删除10。
不同的树结构适用于不同的应用场景,选择合适的树结构可以显著提高程序的性能和效率。在分析为什么MySQL InnoDB存储引擎的索引选择使用B+树之前,我相信很多攻城狮对数据结构中的树还是有些许模糊的,因此就让我们一同踏上这趟由浅入深探讨二叉查找树、AVL树、红黑树、B树和B*树的奇妙之旅,一步步引出B+树以及为什么MySQL InnoDB数据库索引选择使用B+树!领略B+树在数据库索引中应用的神奇魅力。希望通过本文,你能构建起一个体系化的树和索引知识框架,让你在未来的面试和工作中游刃有余。
二叉查找树
二叉查找树(Binary Search Tree, BST)也称为有序二叉树(Ordered Binary Tree)、排序二叉树(sorted binary tree)或者二叉搜索树,是一棵满足以下三个性质的二叉树:
- 有序性:任意非空左子树所有节点的值均小于该节点的值;非空右子树所有节点的值均大于于该节点的值;
- 递归性:任意节点的子树都是二叉查找树;
- 每个节点存储一条记录,且没有键值相等的节点。
从递归定义的角度来看,二叉查找树可以被定义为:要么是一棵空树,要么是由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;而左子树和右子树又同样都是二叉查找树。这种递归定义方式简洁而准确地描述了二叉查找树的结构特点。它作为基础的树形结构,每个节点最多有两个子节点,其递归性和有序性为我们理解更复杂的树结构奠定了基础。
图2 二叉搜索树
如果我们需要查找id=31的记录,利用我们创建的BST,基于二分查找算法实现的查找流程如下:
- 将根节点作为当前节点,把31与当前节点的键值33比较,31小于33,接下来我们把当前节点的左子节点作为当前节点。
- 继续把31和当前节点的键值28比较,发现31大于28,把当前节点的右子节点作为当前节点。
- 把31和当前节点的键值31对比,发现二者相等,满足条件,遍历结束。
所以,我们利用BST只需要3次即可找到目标数据。
二叉树的查找、插入和删除操作的时间复杂度在平均情况下为 O(logn) ,但在最坏情况下,当二叉树退化为链表时,时间复杂度会变为 O(n) 。这是因为在最坏情况下,所有节点都在一条链上,查找、插入和删除都需要遍历整个链表。如下图所示退化的二叉查找树:
二叉树完全不平衡时,查找的时间复杂度就和链表一致了:O(n)。导致这个现象的原因其实是BST变得不平衡了,也就是高度太高了,从而导致查找效率的不稳定。为了解决这个问题,我们需要保证二叉查找树一直保持平衡,从而引出了一个新的定义——平衡二叉树AVL。
AVL树/红黑树
平衡二叉树(Balanced Binary Tree)是一种特殊的、平衡的二叉搜索树,通过严格控制每个节点的平衡因子来保持树的平衡。常见的平衡二叉树有AVL树和红黑树等,在满足BST特性的基础上,具有如下特性:
- 平衡因子限制:要求平衡因子的绝对值不能超过1。
- 递归性质:左右两个子树本身也都是平衡二叉树。
不管是执行插入还是删除操作,只要不满足上面的条件,就要通过旋转树上的节点来保持平衡,使得树的高度始终保持在 O(logn)的范围内。而旋转是非常耗时的,由此我们可以知道AVL树适合用于插入或者删除次数比较少,但查找多的情况。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |