在MySQL中,索引类型是B-tree,访问B-tree中的元素是以对数摊销时间O(log(n))
完成。
另一方面,在哈希表中访问元素是以O(1)
完成的。
为什么在数据库中访问数据时不使用哈希表而使用B-tree呢?
在MySQL中,索引类型是B-tree,访问B-tree中的元素是以对数摊销时间O(log(n))
完成。
另一方面,在哈希表中访问元素是以O(1)
完成的。
为什么在数据库中访问数据时不使用哈希表而使用B-tree呢?
O(1)
而不是log(n)
),这种方式更快,但无法选择范围(介于x
和y
之间的所有元素)。树状算法支持Log(n)
的范围查询,而哈希索引可能导致全表扫描O(n)
。此外,哈希索引的定值开销通常更大(在theta符号中没有因素,但它仍然存在)。另外,树状算法通常更易于维护、随数据增长、扩展等。
哈希索引使用预定义的哈希大小,因此您最终会得到一些“桶”,对象存储在其中。这些对象再次循环以真正找到该分区内正确的对象。因此,如果尺寸较小,则小元素将有很大的开销,而较大的尺寸则会导致进一步扫描。现今的哈希表算法通常是可扩展的,但扩展可能效率低下。
然而,如果索引超过了与哈希大小相比可以容忍的尺寸,那么您的整个索引需要重建。通常这不是问题,但对于非常大的数据库,这可能需要花费数天时间。树状算法的折衷方案很小,适用于几乎所有的用例,并且因此是默认的。但是,如果您有一个非常精确的用例,并且您确切地知道将需要什么,那么您可以利用哈希索引。确实有可扩展的哈希算法。别问我它是如何工作的——对我来说也是一个谜。据我所知,它们起源于可扩展的复制,在这种情况下,重新哈希不容易。
它被称为 RUSH - Replication Under Scalable Hashing,而这些算法因此被称为 RUSH 算法。
实际上,MySQL似乎会根据以下链接使用哈希表或B-tree索引。
使用B-tree和哈希表的区别在于前者允许您在使用=、>、>=、<、<=或BETWEEN运算符的表达式中使用列比较,而后者仅用于使用=或<=>运算符的相等性比较。
哈希表的时间复杂度仅在具有足够大小的情况下才能保持常数级别(必须有足够的桶来容纳数据)。由于数据库表的大小事先未知,因此必须不时地重新散列表格以获得哈希表的最佳性能。重新散列也是昂贵的。
log_100
的值。(InnoDB 的扇出规则是 100;十亿行需要 5 层。) - Rick JamesENGINE=MEMORY
(很少使用)和内部用于“hash-join”。OPTIMIZE
),但这很少值得努力。PRIMARY KEY
排序存储在BTree中。二级索引也存储在单独的BTrees中,但按二级键列排序。叶节点中仅包含PRIMARY KEY
值。因此,二级键查找需要两个BTree查找(除非所有必要的列都在二级+主列中 - 这称为“覆盖”)。我得出的结论是,Big-O可能很有趣,但实现的细节增加了复杂性。并且对于任意大的表性能也很重要。
O(1)
表示法更多的处理过程。首先,你需要运行它通过哈希函数,这个函数会迭代输入字符串的长度,并且每次迭代都有五个或以上的计算步骤。需要注意的是,这些步骤很快,因为它们都在寄存器中完成,而不是在RAM中。接下来,你使用哈希值来获取一个桶(bucket)。我不确定有多少个桶(bucket),或者每个桶(bucket)的长度是多少,但是桶(bucket)是一个数组或链表。然后,你需要遍历桶(bucket)中的项目,并将每个项目与要获取值的输入键进行比较。这又是一个字符串比较。所以,即使是简单的字符串从哈希表中获取值,至少也需要100个计算步骤。所有这些字符串比较加起来就会很多。PRIMARY KEY
BTree必然没有重复项(PK是唯一的)。次要索引隐式包含PK,因此它们也没有重复项。 - Rick JamesPick DB/OS基于哈希,运行良好。如今有更多的内存来支持高效的稀疏哈希表,并且冗余哈希以支持适度范围查询,我认为哈希可能仍然有其用武之地(有些人可能更喜欢其他形式的非范围相似匹配,例如通配符和正则表达式)。我们还建议进行复制,以使碰撞链在内存层次结构具有大的速度差异时保持连续。