数据库索引数据结构总结——ART树就是前缀树

数据库索引数据结构总结

摘要

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

B+Tree

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

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

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

B+Tree

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 保证原子性,从而避免重量级的同步机制。
  • 链表的持久化更加简单。

Skip List Layout

跳表看起来很是像树,好比说检索
Search多线程

跳表横向看来是有不少链表组成,然而指针跳转对于 CPU 缓存 来说很是不友好,能够用纵向数组来实现跳表以增长 CPU 缓存。
Array Skip List并发

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 缓存。

Bw-Tree

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

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

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

ART 结构:
ART

ART 数据节点类型:
Node Types

其主要特色有:

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

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

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

Masstree

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

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

性能对比

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

相关文章
相关标签/搜索