数据库浅谈之常见树结构
HELLO,各位博友好,我是阿呆 🙈🙈🙈
这里是数据库浅谈系列,收录在专栏 DATABASE 中 😜😜😜
本系列阿呆将记录一些数据库领域相关的知识 🏃🏃🏃
OK,兄弟们,废话不多直接开冲 🌞🌞🌞
一 🏠 概述
多路查找树
二叉树中每个节点中包含一个信息,如果节点数多,路径就会很深。即查询时经过了更多节点,造成性能下降
B 树
2-3 树 是最简单的 B 树结构,有如下特点
① 2-3 树所有叶节点都在同一层( B 树均满足该条件)
② 有两个子节点的节点叫二节点,二节点要么没有子节点,要么有两个子节点
③ 有三个子节点的节点叫三节点,三节点要么没有子节点,要么有三个子节点
④ 2-3树是由二节点和三节点构成的树
2-3 树插入规则
按照规则插入一个数到某个节点,若不满足上面 ① ② ③ ,则进行拆分;
先拆上层,若上层满,则拆本层,拆后仍需要满足上面 3 个条件
注 :三节点子树的值大小仍遵守(二叉排序树)规则
B 树的搜索
从根结点开始,对有序序列进行二分查找,命中则结束,或直至叶子结点(叶节点和非叶节点都存放数据,搜索等价于在全集内做二分)
B 树的优点
① 内部通过分裂机制,保持数据有序,重新组织节点,降低树高度提升效率
② 每个节点大小设为 4 K (一页大小) ,只需要一次 I/O 即可完全载入
③ 树高度为 1024,600 亿个元素最多只需要 4 次 I/O 即可读取到想要的元素
B 树的场景
适合于单点查询,例如 MongoDB
缺陷 :所有节点都在磁盘上,读写性能差;不适合进行范围查找(可能在多个节点反复横跳)
B+ 树
它是 B 树的变体,也是一种多路搜索树
B+ 树性质
① 关键字均在叶结点链表中,且有序
② 不可能在非叶结点命中
③ 非叶子结点是叶结点索引,叶结点是存储关键字的数据层
④ 更适合文件索引系统
B 树和 B+ 树有各自应用场景,不能说B+树完全比B树好,反之亦然
非叶节点中仅保留数据之间的相对关系,而所有的真实信息均包含在叶子节点中。把相对关系信息放到内存中,而将所有节点信息(数据)保留在磁盘
查询时通过相对关系,在内存中快速定位到具体节点,从而减少磁盘 IO 次数。另一个优点是通过链表将所有叶节点串联,方便范围查询(例 MySql 存储引擎 InnoDB )
B+ 树信息存放在磁盘中,且属于非顺序写入,所以查询性能很高,但写入性能偏低。在大数据存储和日志服务等需要频繁写入操作领域,就不合适了
B* 树
B+ 树变体,树非根和非叶结点增加指向兄弟的指针,将结点最低利用率从 1/2 提高到 2/3
B+ 树分裂 :当一个结点满时,分配一个新结点,并将原结点中 1/2 数据复制到新结点,最后在父结点中增加新结点的指针;B+ 树分裂只影响原结点和父结点,而不会影响兄弟结点,所以它不需要指向兄弟的指针;
B* 树分裂 :当一个结点满时,如果它的下一个兄弟结点未满,那么将一部分数据移到兄弟结点中,再在原结点插入关键字,最后修改父结点中兄弟结点的关键字(因为兄弟结点的关键字范围改变了);如果兄弟也满了,则在原结点与兄弟结点之间增加新结点,并各复制 1/3 的数据到新结点,最后在父结点增加新结点的指针;
所以,B* 树分配新结点的概率比 B+ 树要低,空间使用率更高
字典树
又称单词查找树,Trie 树 ,是哈希树的一种变种。典型应用是用于统计,排序和保存大量的字符串,所以常被搜索引擎系统用于文本词频统计
优点:利用字符串公共前缀来减少查询时间,最大限度减少无谓字符串比较,查询效率比哈希树高
三个基本性质:
根节点不包含字符,除根节点外每一个节点都只包含一个字符
从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串
每个节点的所有子节点包含的字符都不相同
二 🏠 核心
跳表简单介绍(Skip List)
下图是一个简单有序单链表,查找某个数据,只能从头至尾遍历链表,时间复杂度是 O(n)
对链表进行改造,先对链表中每两个节点建立第一级索引,再对第一级索引每两个节点建立第二级索引
对于上图中的带二级索引的链表中,查询元素 16,先从第二级索引查询 1 -> 7->13,发现 16 大于 13 ,然后通过 13 的 down 指针找到第一级索引的 17,发现 16 小于17 ,再通过13 的 down 指针找到链表中的 16,只需要遍历 6 个节点就完成 16 的查找。
如果在单链表中直接查找 16 的话,只能顺序遍历,需要遍历 10 个节点,效率上有所提升
LSM树(日志结构合并树)
它是基于 Big Table 衍生出的一系列算法操作集合( 磁盘顺序写 + 多个树 ( 状数据结构 ) + 冷热(新老)数据分级 + 定期归并 + 非原地更新),描述了将实时产生的大批量信息在内存中排序、更新,然后按批次顺序写入磁盘固化、合并的流程,实现海量数据的高效存储( RocksDB、LevelDB、HBase )
B+ 树不适合频繁写入,因为它属于非顺序写入,而由于传统磁盘扇区结构,顺序写入性能远好于非顺序写入;相比于 B/B+ 树或者倒排索引,LSM Tree 采用了磁盘顺序写方案,因此具有极高的写吞吐量
数据结构定义
1、LSM 树 横跨内存和磁盘,包含多颗 子树 的森林(分为 Level 0,Level 1,Level 2 … Level n 多颗子树,其中只有Level 0在内存中,其余Level 1-n在磁盘中)
2、内存中 Level 0 子树一般采用排序树(红黑树/AVL树)、跳表等有序数据结构,方便后续顺序写磁盘
3、磁盘中的 Level 1-n 子树,本质是数据排好序后顺序写到磁盘上的文件,只是叫做树而已
4、每一层的子树都有一个阈值大小,达到阈值后会进行合并,合并结果写入下一层
5、只有内存中数据允许原地更新,磁盘上数据的变更只允许追加写,不做原地更新
- 内存中的 Level 0树 在达到阈值后,会在内存中遍历排好序的 Level 0 树并顺序写入磁盘的 Level 1。同样的,在磁盘中的 Level n(n>0)达到阈值时,则会将 Level n 层的多个文件进行归并,写入 Level n+1 层
- 除了内存中的 Level 0 层做原地更新外,对已写入磁盘上的数据,都采用 Append 形式的磁盘顺序写,即更新和删除操作并不去修改老数据,只是简单的追加新数据。右侧蓝色的磁盘部分,Level 1 和 Level 2 均包含 key 为 2 的数据,同时左侧绿色内存中的 Level 0 树也包含 key 为 2 的数据节点
LSM 增删改查
插入 :往内存中 Level 0 排序树丢即可,并不关心数据是否在内存或磁盘中存在(已存在则场景转换成更新操作)
删除 :并不是直接删除,而是通过 墓碑标记 的特殊数据来标识数据删除;
删除分为:待删除数据在内存中、待删除数据在磁盘中 和 该数据不存在 三种情况
修改 :和删除操作相似,也是分为三种情况:待修改数据在内存中、在磁盘中和 该数据不存在
查询 :按顺序查找 Level 0、Level 1、Level 2 … Level n ,一旦匹配则返回目标数据(策略保证查到的是最新版本数据,类似 MVCC )
LSM 合并
合并原因 :一 内存不是无限大,Level 0 树达到阈值时,需将数据从内存刷到磁盘中;二 需对磁盘上达到阈值的顺序文件进行归并,并将归并结果写入下一层,过程中会清理重复数据和被删除数据 (墓碑标记)
优缺点分析
优:增、删、改操作快,写吞吐量高
缺:读操作被弱化,不擅长区间范围读操作, 归并耗资源
LSM 树通过舍弃部分读性能,换取了高写性能,适用于写吞吐量远大于读吞吐量场景
设计原则 :
- 先内存再磁盘
- 内存原地更新
- 磁盘追加更新
- 归并保留新值
三 🏠 结语
身处于这个浮躁的社会,却有耐心看到这里,你一定是个很厉害的人吧 👍👍👍
各位博友觉得文章有帮助的话,别忘了点赞 + 关注哦,你们的鼓励就是我最大的动力
博主还会不断更新更优质的内容,加油吧!技术人! 💪💪💪