数据库索引数据结构总结

from:https://zhewuzhou.github.io/2018/10/18/Database-Indexes/

摘要

数据库索引是数据库中最重要的组成部分,而索引的数据结构设计对数据库的性能有重要的影响。本文尝试选取几种典型的索引数据结构,总结分析,以窥数据库索引之全貌。

B+Tree

B+Tree 是一种树数据结构,是一个n叉排序树,每个节点通常有多个孩子,一棵B+Tree包含根节点、内部节点和叶子节点。根节点可能是一个叶子节点,也可能是一个包含两个或两个以上孩子节点的节点。

B+Tree 几乎是数据库默认的索引实现,其细节如下:

维基百科在 B+ 树中的节点通常被表示为一组有序的元素和子指针。如果此B+树的序数(order)是m ,则除了根之外的每个节点都包含最少⌊m/2⌋⌊m/2⌋⌊m/2⌋⌊m/2⌋ 个元素最多 m-1 个元素,对于任意的节点有最多 m 个子指针。对于所有内部节点,子指针的数目总是比元素的数目多一个。因为所有叶子都在相同的高度上,节点通常不包含确定它们是叶子还是内部节点的方式。
每个内部节点的元素充当分开它的子树的分离值。例如,如果内部节点有三个子节点(或子树)则它必须有两个分离值或元素 a1 和 a2。在最左子树中所有的值都小于等于 a1,在中间子树中所有的值都在 a1 和 a2 之间((a1,a2]),而在最右子树中所有的值都大于 a2。

B+Tree 有如下性质:

  1. 查询时间复杂度为 O(logmn)O(logm⁡n)
  2. 插入时间复杂度 O(logmn)O(logm⁡n)
  3. 删除时间复杂度 O(logmn)O(logm⁡n)
  4. 搜索一个范围的键(k 个键)时间复杂度为 O(logmn+k)O(logm⁡n+k)

B+ Tree 的多线程同步

  • 搜索:从根节点开始,获取子节点的读闩,然后释放父节点的读闩;重复这个过程,直到找到目标节点位置。
  • 插入/删除:从根节点开始,获取子节点的写闩;重复这个过程,直到找到目标节点位置;如果子节点是安全的,插入/删除不会引起树结构的变化即父节点不需要调整,可释放所有祖先写闩;乐观的插入/删除是先走搜索获得目标节点的读闩,如果目标节点并不安全,则回归上述从根节点获得写闩的过程。

Skip List(跳表)

Skip List是一种随机化的数据结构,基于并联的链表,其效率可比拟于二叉查找树(对于大多数操作需要O(log n)平均时间)。基本上,跳跃列表是对有序的链表增加上附加的前进链接,增加是以随机化的方式进行的,所以在列表中的查找可以快速的跳过部分列表(因此得名)。所有操作都以对数随机化的时间进行。Skip List可以很好解决有序链表查找特定值的困难。

一个跳表,应该具有以下特征:

  1. 一个跳表应该有几个层(level)组成;
  2. 跳表的第一层包含所有的元素;
  3. 每一层都是一个有序的链表;
  4. 如果元素x出现在第i层,则所有比i小的层都包含x;
  5. 第i层的元素通过一个down指针指向下一层拥有相同值的元素;
  6. 在每一层中,-1和1两个元素都出现(分别表示INT_MIN和INT_MAX);
  7. Top指针指向最高层的第一个元素。

相对于 B+Tree,Skip List 有如下优势:

  • B+ Tree 的插入删除操作有可能会引起树结构的变化,需要从新平衡;与之相对的,跳表插入要简单的多,更加简单高效。
  • B+ Tree 的实现诸如保持树平衡非常复杂;与之相对的,跳表并没有非常复杂的逻辑,实现相对更加简单。
  • 取下一个元素可以再常数时间内,相对于 B+ Tree 的对数时间。
  • 因为链表非常简单,可以很容易的修改跳表结构,以更好地支持诸如范围索引之类的操作。
  • 链表结构使得多线程修改可以仅用 CAS 保证原子性,从而避免重量级的同步机制。
  • 链表的持久化更加简单。

跳表看起来非常像树,比如说检索

跳表横向看来是有很多链表组成,然而指针跳转对于 CPU 缓存 来讲非常不友好,可以用纵向数组来实现跳表以增加 CPU 缓存。

Bw-Tree

Hekaton 是微软 SQLServer 专门针对 OLTP 应用场景进行优化的数据库引擎,其索引实现基于 Bw-Tree。Bw-Tree 是一种无需使用任何闩同步的 B+Tree,其主要设计思想如下:

  1. Mapping Table(映射表) 映射表存储内存页的ID与其对应的物理内存地址,使得线程可以通过访问映射表找到需要方位的内存地址,映射表的更新通过CAS操作。
  2. 不直接修改节点,任何的更新操作都会生成新的数据并通过指针指向被更新节点;新生成的数据所导致的元数据的修改,比如修改映射表都通过 CAS 完成。
  3. 垃圾回收,Bw-Tree 通过不断新增数据的方式避免直接修改树节点,在树不断更新的过程中,不可避免的会产生很多垃圾,因此 Bw-Tree 实现了基于 Epoch 的垃圾回收机制:当一个线程想保护一个它正在使用但是将会被回收的对象,例如检索的时候,访问了一个内存页,就把当前线程加入 Epoch,当这个线程完成检索页面的操作后,就会退出 Epoch。通常一个线程在一个epoch的时间间隔内完成一次操作,例如检索。在线程成功加入 Epoch 的时候,可能会看到将要被释放的老版本的对象,但不可能看到已经在前一个 Epoch 中释放的对象,因为其在当前 Epoch 中的操作并不依赖上一个 Epoch 中的数据。因此,一旦所有的线程成功加入Epoch 并完成操作然后退出这个Epoch,回收该 Epoch 中的所有对象是安全的。

由于维护了映射表,和新增数据链,因此树结构调整相对复杂,不仅仅要调整树,切要保证树结构和映射表之间的关系。具体操作可参考此篇文章。

尽管实现非常复杂,Bw-Tree 作为无锁的数据库索引树,有如下优势:

  • 无闩: 实现无锁数据结构十分困难,Bw-Tree 在多线程场景下没有引入任何的闩,只使用 CAS 指令保证线程同步,因此多核的扩展性优于普通用闩同步的B+Tree。
  • CPU 缓存: 由于不直接修改节点而是追加修改补丁,因此 CPU 缓存不会应为更新数据而失效,因此可以显著提高 CPU 缓存命中率。微软论文中的数据表明,90% 的读操作数据来自 CPU L1/L2 缓存。

Adaptive Radix Tree(自适应基数/前缀树,ART)

Radix Tree (基数树)是一种常见的前缀树,Linux Kernel 文件系统就用到了该数据结构:

]Hyper 数据库中实现了 Adaptive Radix Tree (自适应基数/前缀树,ART)作为其索引。基数树的每个节点可以存储任意长度的键切片,比如 Linux Kernel 中的基数树每个节点存储 6位的键切片;然而数据库索引很多场景下会被频繁修改,每个节点固定长度的键切片会造成时间(切片过长)和空间上(切片过短)的浪费,因此,Hyper 实现了自适应的基数树,也就是节点根据长度的不同分成若干种,随着数据的变化而自行调整。

ART 结构:

ART 数据节点类型:

其主要特点有:

  • 树的高度仅取决于键长度。
  • 更新和删除不涉及到树结构的调整,不需要平衡操作。
  • 到达叶子节点的路径就是键。
  • 时间复杂度取决于键的长度,而跟数据量无关,如果数据的增加远远超过键长度的增加,那么使用 ART 将会在性能上带来非常大的收益。

讲述ART同步的论文中提供了描述了两种ART的同步机制:

  1. 乐观锁:

    • 读不阻塞写
    • 写操作在获得对应的节点闩之后,更新版本信息
    • 读操作在读下一个结点前,检查版本信息是否发生改变
  2. 乐观读悲观写
    • 所有的节点都包含一个互斥锁,当某一个读操作获得此互斥锁之后,阻塞其他写操作
    • 读操作不用获取任何的锁或者闩,也不用检查版本信息
    • 写操作保证同一个节点读操作的数据一致性,即写操作使用原子指令进行写入

Masstree

2012年发表的论文 Cache craftiness for fast multicore key-value storage 提出了 Masstree,其特点如下:

  • 可以理解为B+ Tree 和 Radix Tree 的混合体,即将键切分成多个部分,每个部分为一个节点;每个节点内部又是一个 B+ Tree,兼顾空间和性能。
  • Masstree将变长键划分成多个固长部分,每个固长部分可以通过int类型表示,而不是char类型。由于处理器处理int类型比较操作的速度远远快于char数组的比较,因此Masstree通过int类型的比较进一步加速了查找过程。固定长度可以设置为 CPU 缓存行长度,以增加 CPU 缓存效率。
  • 每个节点是一个 B+ Tree,因此 CPU 在查询的时候可以将节点所代表的B+ Tree 加载到 CPU 缓存中,以增加 CPU 缓存命中率。
  • 其并发控制用到了Read-Copy-Update(RCU)。读不因任何数据更新而阻塞,但更新数据的时候,需要先复制一份副本,在副本上完成修改,再一次性地替换旧数据。因此读不会造成 CPU 缓存无效。

性能对比

上述几种索引数据结构性能对比如下:

转载于:https://www.cnblogs.com/bonelee/p/11497565.html

数据库索引数据结构总结——ART树就是前缀树相关推荐

  1. 分门别类刷leetcode——高级数据结构(字典树,前缀树,trie树,并查集,线段树)

    目录 Trie树(字典树.前缀树)的基础知识 字典树的节点表示 字典树构造的例子 字典树的前序遍历 获取字典树中全部单词 字典树的整体功能 字典树的插入操作 字典树的搜索操作 字典树的前缀查询 字典树 ...

  2. 实现字典树(前缀树、Trie树)并详解其应用

    今天看到一个比较好的数据结构,字典树,做一下记录,以供自己后期复习和读者朋友的参考. 1.定义 字典树又称单词查找树.前缀树.Trie树等,是一种树形结构,是一种哈希树的变种.典型应用是用于统计,排序 ...

  3. trie(字典树、前缀树)

    trie(字典树.前缀树) 1. trie原理 原理 trie树,又被称为字典树.前缀树,是一种高效地存储和查找字符串集合的数据结构. 一般来说,用到trie的题目中的字母要么全是小写字母,要么全是大 ...

  4. 字典树(前缀树)-Java实现

    字典树 字典树是一种树形结构,优点是利用字符串的公共前缀来节约存储空间.在这提供一个自己写的Java实现,非常简洁. 根节点没有字符路径.除根节点外,每一个节点都被一个字符路径找到. 从根节点到某一节 ...

  5. Java Trie字典树,前缀树

    Trie查询每个条目的时间复杂度,和字典中一共有多少条无关. 时间复杂度为O(W) w为查询单词的长度 import java.util.TreeMap;public class Trie {priv ...

  6. 字典树/Trie/前缀树-LeetCode总结:720词典中最长的单词;127. 单词接龙;677. 键值映射;面试题 17.17. 多次搜索;648. 单词替换

    MyTrie结构体和相关操作函数 typedef struct MyTrie {bool is_word;vector<MyTrie*> next;MyTrie():is_word(fal ...

  7. Trie (字典树,前缀树)

    一,内容 (一),概念 详情可见:详解Trie 插入过程(insert)          对于一个单词,从根开始,沿着单词的各个字母所对应的树中的节点分支向下走,直到单词遍历完,将最后的节点进行标记 ...

  8. 高度为5的3阶b树含有的关键字个数_B-树和B+树的应用:数据搜索和数据库索引...

    B-树 1 .B-树定义:有序数组+平衡多叉树 B-树是一种平衡的多路查找树,它在文件系统中很有用. 定义:一棵m 阶的B-树,或者为空树,或为满足下列特性的m 叉树: ⑴树中每个结点至多有m 棵子树 ...

  9. 树-阶数-B+树-B树-数据库索引方式

    树的阶数: 我们描述一颗B树时需要指定它的阶数,阶数表示了一个结点最多有多少个孩子结点,一般用字母m表示阶数.当m取2时,就是我们常见的二叉搜索树. 一颗m阶的B树定义如下: 1)每个结点最多有m-1 ...

最新文章

  1. 麦芒8能安装鸿蒙系统吗,首颗5G基带芯片麦芒8发布鸿蒙最新进展
  2. STC10F10XE定时器中断输出10KHz的方波程序
  3. 用于matplotlib对齐很有用的算法,可用于面试笔试
  4. Docker端口映射实现
  5. SqlServer安装出错解决办法
  6. powerdesigner使用之——从“概念模型”到“物理模型”
  7. C++爬虫项目爬取图片
  8. JS-随机生成的密码
  9. 图Graph--拓扑排序(Topological Sorting)
  10. 系统目录结构 ls命令 文件类型 alias命令
  11. HTML如何实现斜体字
  12. 2021年中国宠物牙膏市场趋势报告、技术动态创新及2027年市场预测
  13. 蓝桥杯 ALGO-79 算法训练 删除数组零元素
  14. centos7 keeplive+lvs
  15. 算法竞赛入门经典(第二版) —— 第一章 程序设计入门
  16. 阿里datav地图json地址
  17. html左斜杠转义字符,html的右斜杠转义符号是什么呢
  18. 360 面试 一面+二面
  19. golang sync/atomic
  20. 【cocos2d-x 大型ARPG手游研发----地图活起来了】

热门文章

  1. c语言prime函数怎么用_n!函数用C语言其实可以这样!
  2. apache安装_Ubuntu20.04安装Sql+apache+php
  3. Java如何读取JAR包外的properties文件及打成jar包后无法读取到jar包内的properties文件
  4. Python工具包werkzeug
  5. github 下载单个文件夹_从Github上下载单个文件夹的快速方式
  6. python录制视频和声音_python录制系统声音
  7. cv python 样例_【CV实战】OpenCV—Hello world代码示例
  8. 轴只显示5个刻度_组团投资5亿元!武平集中签约5个新型显示产业链投资项目
  9. mac睡眠快捷键_mac键盘快捷键大全
  10. ateq测漏仪f620说明书_上海壁挂式测漏仪安全使用说明,煤气房报警器安装安全使用说明...