高级数据库八:不需要锁和闩的索引(一)

不需要锁和闩的索引(Latch-free OLTP Indexes Part I)

T-Trees

T-Trees 是一种基于AVL树的数据结构,它的设计是人们针对内存数据库做的优化。

不像B-Trees 系列在硬盘上那样存储大量的信息,包括索引、值等等,T-Trees 利用了所有数据都已经在内存中的这个条件,它存储的是指向数据的指针。这样可以有效地减少overhead,具有较高的节点空间占有率;平衡二叉树的实现也更加简单。

但是它在形成之后更难去维护平衡,也更难完成安全的并发访问。

上图是一个T-Trees的示意图,它有指向左右孩子和父亲节点的指针,中间三个指针(多个指针)是按顺序值的排序的,最边上表示的是子树的边界值(唯一存值的地方),inclusive。

跳表(Skip Lists)

实现有序动态索引的最简单方法是使用排序的链接列表。
所有的操作都要进行线性搜索,那么平静时间复杂度是 O(N)

那么就可以使用跳表,大家可以直接去百度一下具体的讲解。

搜索的复杂度是 O(log N)

跳表的优点是:

  1. 插入删除时不需要维护平衡
  2. 占用较小的内存
  3. 有可能只需要用CAS指令就能够实现跳表的并发访问

关于CAS指令的并发操作
以INSERT K5为例子,在这儿我只讲了一些操作思想,具体的实现可以看看跳表的源代码

  1. 第一层,K4直接就是连接到K6;第二层,K4直接连接到无穷;
  2. 将K5的节点初始化,但是不做任何连接,如图中第二层,第三层所示;
  3. 将第一层的K4连接到K5,K5连接到K6,只需要交换指针即可;
  4. 同理对应剩下的层数。

删除的话,就打了一个标记,暂时做逻辑删除

然后再从上往下将它的连接断开。

跳表的缺点是:

  1. 对缓存不友好,没有对局部引用进行优化(可以在一个节点中存储多个key和value
  2. 每次插入多次调用随机数发生器很慢
  3. 无法反向查询(可以用stack做


关于stack的操作,这一段我有点没听明白。以下是我的分析和理解,不一定对。
我一开始以为反向查询指的是,我们在查询的过程中,会有返回上一个位置,并查询下一层的操作(大家注意看查找19的那张图,有一个反向的操作)。如果是这样的操作,就非常类似递归调用,只是这儿通过的是手工栈来实现的。
在ACM竞赛中为啥用手工栈的原因有很多,比如,程序自己的递归栈存的东西较多,也需要调用与传参,空间时间有一定损耗;程序的栈递归深度有限,且程序栈区的内存分配较小。这儿用的原因我就不懂了。
但是我可以清楚地知道,如果使用的是双向链表来实现上一个节点的记录,这样内存就凭空多了一个 O(N) ,显得非常蠢。
在看到下图的时候,我大概有一点猜想

stack可以用于存储一个range query的过程,而这个过程在SQL中定义了ORDER BY,且这个ORDER是按照存储的逆序排序的。
这儿放上一个代码链接,在这个代码里有MemSQL关于跳表的一些说明,同时也说到了stack的问题,大家可以去看看。

Index Implementation Issues

内存池(Memory Pools)

我们在插入和删除节点的时候,我们不可能每次都调用一个malloc和free,这样的效率非常非常低。所以我们干脆先申请一大块内存,这一大块内存就是内存池。

内存池的使用非常广泛,而且也需要一定的策略去维护它,维护包括,resize,reorganize等等。

垃圾回收(Garbage Collection)

我们需要知道什么时候才能对一个已经标记删除的节点重新使用。

如果你在还没有将K2的指针指到K4,就直接将K3的内存用于别的事情,那么K2的指针就变成悬挂指针了,而K4就变成了孤岛。

计时器

为每个节点维护一个计数器来跟踪正在访问的线程数。

  • 访问前增加计数器。
  • 完成后减少。
  • 计数为零时,节点能安全删除。

但是这个在多核CPU上表现非常糟糕,因为大量的加减操作会导致缓存的一致性错误。

周期垃圾回收

用类似Read-Copy-Update (RCU)的技术,每一个周期(比如,10ms),统计哪些线程访问了这个索引。

在一个周期的内标记这个节点已经被删除,组织其他线程访问,在所有其他已经进入的线程退出的情况下,就可以删除该节点。

不唯一索引(NON-UNIQUE INDEXES)

存储多个键/值

用链表存值

类似用hash表的链式存储解决冲突

参考资料

课件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值