B树与哈希表

时间:2011-09-05 09:43:18

标签: mysql computer-science complexity-theory b-tree

在MySQL中,索引类型是b树,访问b树中的元素的是对数摊销时间O(log(n))

另一方面,访问哈希表中的元素位于O(1)

为什么不使用哈希表而不是b-tree来访问数据库中的数据?

8 个答案:

答案 0 :(得分:85)

您只能通过哈希表中的主键访问元素。 这比使用树算法( O(1)而不是log(n) )更快,但您无法选择范围( x和{{之间的所有内容1}} 的)。 树算法在y中支持此功能,而哈希索引可以导致全表扫描Log(n)。 哈希索引的常量开销通常也更大(,这不是theta表示法的因素,但它仍然存在)。 树算法通常也更容易维护,随着数据,规模等而增长。

散列索引使用预定义的散列大小,因此您最终会得到存储对象的“桶”。这些对象再次循环,以便在此分区中找到正确的对象。

因此,如果您的尺寸较小,则对于小尺寸元素会产生大量开销,因此大尺寸会导致进一步扫描。

今天的哈希表算法通常会缩放,但缩放可能效率低下。

  

确实存在可扩展的散列算法。不要问我这是怎么回事 - 对我来说这也是一个谜。 AFAIK是从可扩展复制发展而来的,其中重新散列并不容易。

     

其名为 RUSH - R 明显 U nder S 可销售 H 灰化,这些算法因此被称为RUSH算法。

但是,与散列大小相比,索引可能超出容许大小,并且需要重新构建整个索引。通常这不是问题,但对于巨大的庞大数据库,这可能需要数天时间。

树算法的权衡很小,它们几乎适用于所有用例,因此是默认的。

但是,如果您有一个非常精确的用例并且您确切地知道需要什么,那么您可以利用散列索引。

答案 1 :(得分:56)

实际上,根据以下link,MySQL似乎使用散列表或b树这两种索引。

使用b-tree和哈希表之间的区别在于前者允许你在使用=,>,> =,<,&lt的表达式中使用列比较 ; =,或BETWEEN运算符,而后者仅使用进行相等比较,使用=或< =>运算符。

答案 2 :(得分:13)

哈希表的时间复杂度仅对于足够大小的哈希表是恒定的(需要有足够的桶来保存数据)。事先不知道数据库表的大小,因此必须立即对表进行重新分析,以便从哈希表中获得最佳性能。重组也很昂贵。

答案 3 :(得分:5)

我认为Hashmaps也不会扩展,并且在需要重新整理整个地图时可能会很昂贵。

答案 4 :(得分:1)

除了这里的好答案之外,这里还有一些关于如何构建数据库的观点。

首先,健壮哈希表通常使用分桶系统完成,例如用于实现 JavaScript“对象”(即哈希表)的 Quadratic Probing。您可以在 JavaScript here 中看到分桶哈希表的实现。

您会注意到,在此实现中,进行的处理比 O(1) 表示法所看到的要多得多。首先,您通过散列函数运行它,该函数迭代输入字符串的长度,并且每次迭代有 5 个以上的计算步骤。但请注意,这些是快速计算步骤,因为它们都是在寄存器中完成的,而不是在 RAM 中。接下来,您使用该哈希值来获取 bucket。我不确定有多少个桶,或者一个桶有多长,但这个桶是一个数组或链表。因此,然后您遍历存储桶项目,并将每个项目与您要为其获取值的输入键进行比较。这又是一个字符串比较。因此,我很可能估计即使是一个简单的字符串也至少需要 100 个计算步骤才能从哈希表中获取它。所有这些字符串比较加起来。

此外,桶可能是半空的,这会占用大量无用的空间。最后,当哈希表的占用率达到一定大小时,它的大小必须加倍!它必须重新处理和重新计算一切。这可能会导致 UI 应用程序出现明显故障。

另一方面,B+树是一种更紧凑的数据结构。您仍在进行字符串比较,但您只是跳过 MAX 我会说树中的 20 个链接(就深度而言),然后扫描最后一个树节点中的子节点以找到完全匹配。

从这个意义上说,我认为实际上 B+树或 B 树将与哈希表相当,尤其是幼稚的实现。两个系统都可以优化和微调,我仍然认为它们会接近相等。只有测试会告诉你。但是树具有更紧凑的内存优势。因此,在考虑了很长时间并权衡了方程式的各个方面之后,我将选择 B+树作为快速查找项目的理想解决方案。

答案 5 :(得分:1)

  • MySQL 仅在几种情况下支持 HASH:ENGINE=MEMORY(很少使用)和内部用于“哈希连接”。
  • 即使您要求 InnoDB 表具有 HASH 索引,它也会默默地将其转换为 BTree。
  • 哈希接近 O(1),但从技术上讲,在最坏的情况下它更像是 O(N^2)。这是因为需要处理“冲突”。
  • MySQL 选择 BTree 是因为它比 Hash 更灵活(因为它可以处理范围),而且速度并不比 BTree 慢得多。
  • 可以说,由于块的缓存,BTree 比 O(1) 慢。非叶节点往往会被缓存并留在 RAM 中,即使叶节点来来去去也是如此。
  • MySQL 动态维护一个 BTree;虽然您可以要求重建索引(参见 OPTIMIZE),但很少值得付出努力。
  • 在 InnoDB 中。数据存储在由 PRIMARY KEY 排序的 BTree 中。辅助键也存储在 BTree 中,但按辅助键列排序。那么只有叶节点中的其他信息是 PRIMARY KEY 值。因此,辅助键查找需要两次 BTree 查找(除非所有必需的列都在辅助 + 主列中——这称为“覆盖”)。

最后我说 Big-O 可能很有趣,但实现的细节增加了复杂性。以及任意大表的性能。

答案 6 :(得分:0)

Pick DB / OS基于哈希,并且运行良好。如今,有了更多的内存来支持有效的稀疏哈希表,并使用冗余哈希来支持适度的范围查询,我想说哈希可能仍然占有一席之地(有些人宁愿使用其他形式的非范围相似性匹配,例如通配符和正则表达式)。我们还建议进行复制,以在内存层次结构具有较大速度差异时使冲突链保持连续。

答案 7 :(得分:0)

另一件事也可能影响选择:哈希表可以很好地将一个键映射到一个单一的值。但是,在一个键映射到大量元素(对于表的单列非常常见)的情况下,您很容易失去 O(1) 行为,具体取决于它的处理方式。 BTrees 没有这个问题并且可以很好地处理大量重复条目。