任何人都可以解释为什么数据库倾向于使用b树索引而不是有序元素的链表。
我的想法是:在B + Tree(大多数数据库使用)上,非叶节点是指向其他节点的指针的集合。每个集合(节点)都是有序列表。叶节点是所有数据指针所在的位置,是数据指针簇的链表。
非叶节点仅用于查找目标数据指针所在的正确叶节点。因为叶节点就像一个链表,那么为什么不只是取消树元素而只是拥有链表。可以提供元数据,其给出每个叶节点集群的最小值和最大值,因此应用程序可以只读取元数据并找到数据指针所在的正确叶。
为了清楚起见,用于搜索随机访问的有序列表的最有效算法是二进制搜索,其性能为O(log n),与b树相同。使用链表而不是树的好处是它们不需要平衡。
这种结构是否可行。
答案 0 :(得分:14)
经过一些研究和论文阅读后,我找到了答案。
为了处理如此数百万条记录的大量数据,必须将索引组织成群集。群集是磁盘上的一组连续扇区,可以快速读入内存。这些通常大约4096字节。
这些群集中的每一个都可以包含一堆索引,这些索引可以指向磁盘上的其他群集或数据。因此,如果我们有一个链表索引,索引的每个元素都将由一个集群中包含的索引集合组成(比如说100)。
因此,当我们寻找特定记录时,我们如何知道它所在的群集。我们执行二进制搜索以找到有问题的集群[O(log n)]。
但是,要进行二进制搜索,我们需要知道每个聚类中值的范围,因此我们需要元数据来说明每个聚类的最小值和最大值以及该聚类的位置。这很棒。除非每个集群可以包含100个索引,并且我们的元数据也保存在单个集群上(对于速度),那么我们的元数据只能指向100个集群。
如果我们想要超过100个集群会发生什么。我们必须有两个元数据索引,每个索引指向100个集群(10 000个记录)。那还不够。让我们添加另一个元数据集群,现在我们可以访问1 000 000条记录。那么我们如何知道我们需要查询三个元数据集群中的哪一个才能找到我们的目标数据集群。我们可以搜索一个然后另一个,但这不会扩展。所以我添加了另一个元元数据集群来指示我应该查询三个元数据集群中的哪一个来查找目标数据集群。现在我有一棵树!
这就是数据库使用树的原因。它不是索引大小的速度,也不是索引引用其他索引的需要。我上面描述的是B + Tree - 子节点包含对其他子节点或叶节点的引用,叶节点包含对磁盘上数据的引用。
呼!
答案 1 :(得分:5)
我想我在SQL索引教程的第1章中回答了这个问题:http://use-the-index-luke.com/sql/anatomy
总结最重要的部分,就您的具体问题而言:
- 来自“The Leaf Nodes”
索引的主要目的是提供有序的 索引数据的表示。但是,这是不可能的 因为insert语句需要,所以按顺序存储数据 移动以下条目以为新的条目腾出空间。但感动 大量数据非常耗时,因此插入 声明会很慢。问题的解决方案是建立一个 逻辑顺序,与内存中的物理顺序无关。
- 来自“B-Tree”:
索引叶节点以任意顺序存储 - 位置在上 磁盘根据不符合逻辑位置 指数订单。它就像一个带有洗牌页面的电话簿。如果 你搜索“史密斯”,但在第一个“罗宾逊”打开它 这个地方,绝不是史密斯更远的地方。 数据库需要第二个结构来快速找到其中的条目 混乱的页面:平衡的搜索树 - 简而言之:B-Tree。
答案 2 :(得分:2)
链接列表通常不是按键值排序,而是按插入时刻排序:插入在列表末尾完成,每个新条目都包含指向列表上一个条目的指针。
它们通常被实现为堆结构。
这有两个主要好处:
它们非常易于管理(您只需要指向每个元素的指针)
如果与索引结合使用,您可以克服顺序访问的问题。
如果您按键值使用有序列表,则可以轻松访问(二进制搜索),但每次编辑,删除,插入新元素时都会遇到问题:您必须在执行后保持列表的顺序排列操作,使算法更加复杂和耗时。
B +树是更好的结构,拥有你陈述的所有属性,以及其他优点:
您可以使用相同的单个搜索成本进行组搜索(按键值的间隔):由于插入算法,因此叶子中的元素会自动排序,这在链接列表中是不可能的,因为它会需要对列表进行多次线性搜索。
成本与所包含的元素数量成对数,特别是因为这些结构保持平衡,访问成本并不取决于您所寻求的特定值(非常有用)。
这些结构在更新,插入或删除操作方面非常有效。