使用两个数据库来说明此示例:CouchDB和Cassandra。
CouchDB使用B + Tree作为文档索引(使用a clever modification在其仅附加环境中工作) - 更具体地说,当文档被修改(插入/更新/删除)时,它们被附加到正在运行的数据库文件中以及完整的叶 - >来自所有节点的B +树的节点路径受到文档之后的更新版本的影响。
这些分段修改的索引修订版本与修改一起内联,使得完整索引是附加在文件末尾的最新索引修改的联合,以及在数据文件中进一步返回的仍然相关的其他部分并且尚未修改。
搜索B+ tree 是O(登录)。
Cassandra将记录键在内存中保存在表中(让我们将它们视为此问题的数组),并将它们作为单独的(已排序的)sorted-string tables不时写出来。
我们可以将所有这些表的集合视为“索引”(根据我的理解)。
Cassandra有时需要compact/combine these sorted-string tables,创建索引的更完整的文件表示。
搜索a sorted array是O(登录)。
假设在CouchDB中维护部分B +树块与Cassandra中的部分排序字符串索引之间存在类似的复杂程度,并且假设两者都提供O(logn)搜索时间,您认为哪一个可以更好地表示数据库索引和为什么?
我特别好奇是否有一个关于一个的实现细节使其特别有吸引力或者如果它们都是一个洗,你只需选择你喜欢使用的数据结构/对开发者来说更有意义。
感谢您的想法。
答案 0 :(得分:51)
将BTree索引与SSTable索引进行比较时,应考虑写入复杂性:
当写入随机写入BTree时,您将进行随机读取(以执行叶节点和路径的复制)。因此,虽然写入顺序在磁盘上,但对于大于RAM的数据集,这些随机读取将很快成为瓶颈。对于类似SSTable的索引,写入时不会发生此类读取 - 只会进行顺序写入。
您还应该考虑在更糟糕的情况下,对BTree的每次更新都可能产生log_b N IO - 也就是说,您最终可能会为每个密钥写入3或4个块。如果密钥大小远小于块大小,则这非常昂贵。对于类似SSTable的索引,每个写入IO将包含尽可能多的新密钥,因此每个密钥的IO成本更像是1 / B.
在实践中,这使得SSTable比BTree快数千倍(对于随机写入)。
在考虑实现细节时,我们发现实现类似SSTable的索引(几乎)无锁定要容易得多,因为BTrees的锁定策略变得非常复杂。
您还应该重新考虑您的阅读费用。对于随机点读取,你是正确的,而不是BTree是O(log_b N)随机IO,但是类似SSTable的索引实际上是O(#sstables.log_b N)。如果没有合适的合并方案,#sstables与N成正比。有各种各样的技巧可以解决这个问题(例如使用布隆过滤器),但这些对小型随机范围查询没有帮助。这就是我们在Cassandra中找到的:
http://www.acunu.com/blogs/richard-low/cassandra-under-heavy-write-load-part-ii/
这就是为什么Castle,我们的(GPL)存储引擎确实合并稍有不同,并且可以在写入性能略有折衷的情况下实现更好的(O(log ^ 2 N))范围查询性能(O(log) ^ 2 N / B))。在实践中,我们发现它比Cassandra的SSTable写入索引更快。
如果您想了解更多相关信息,我已经谈过它的工作原理:
答案 1 :(得分:9)
答案 2 :(得分:1)
LSM-Trees在存储引擎结构上优于B-Trees。 它以某种方式将随机写入转换为aof。 这是一个LSM-Tree src: https://github.com/shuttler/lsmtree
答案 3 :(得分:1)
每种方法都应该提到一些事项:
O(logn)
。但是,单个数据库写入可能会导致存储系统中的多次写入。例如,当节点已满时,必须将其拆分,这意味着将有2个写入用于2个新节点,1个额外写入用于更新父节点。如果父节点也已满,您可以看到它会如何增加。O(logn)
。但是,要记住它们是在内存中完成的,因此它们应该比B树磁盘中的对数运算快几个数量级。为了完整起见,我们应该提到写入也写入预写日志以进行崩溃恢复。但是,鉴于这些都是顺序写入,预计它们比B树的随机写入更有效。显而易见,这两种方法之间的比较要复杂得多。在极其简化的尝试中提供具体的比较,我想我们可以这样说:
参考