问题如下:
postgresql(或其他数据库实现)是否针对聚集索引进行O(1)查找? 即,从行的id(其中id列是聚集索引)直接查找文件系统上的行位置
如果无法进行此类查找,是否通过id log2n查找行?
这些问题源自实现多对多关系所需的以下联结表:
junction_table:
parent_id
child_id
检索一组child_ids
select * from junction_table where parent_id=parent_value
从根本上说,正确的实现应该为子行生成一组位置 更糟糕的是,至少有一种从child_ids集计算子行位置的方法
VS一对多查询,它产生子行的方向位置:
one_to_many_child_table:
id
name
parent_id
select * from child_table where p_id=parent_value
答案 0 :(得分:1)
许多问题 - 让我提一下,把各个部分放在一起。
BTrees ,本质上是O(logn)。但是,你可以把它想象成O(1)。 BTree通常在每个节点中具有100个子链接。这表示一百万行只有3级深度;一个万亿行将大约6个级别。
此外,LRU缓存(例如MySQL在块级别执行)往往至少保留缓存中的非叶节点。 (在缓存中拥有所需的是大型数据库的真正的优化。)
B + Tree - 获取BTree并在叶节点之间添加双向链接。这使得“范围扫描”非常有效。
B + Tree索引是“最佳整体”。
群集在此上下文中,假设“群集”意味着唯一行标识符与数据一起存储。 (对于MySQL,这是PRIMARY KEY
;其他一些我们是'rownum'。)
PRIMARY KEY 可以是群集和/或唯一的 - 这随数据库实施而变化。
辅助密钥通常是BTree,但从它到数据的方式是以不同的方式实现的。它可能直接指向数据;它可能有一个“rownum”,可用于查找记录;或者它可能有主键的副本,从而允许通过PK查找行。
MyISAM的InnoDB - PRIMARY KEY
与数据集群,组织为B +树,并且是唯一的。这意味着PK的点查询将在BTree中进行一次潜水以找到整行。
InnoDB中的辅助密钥具有单独的BTree,并且在叶节点中找到PK的副本。因此,二级密钥查找是两次潜水(一次在BTree中,一次在PK +数据BTree中)。也就是说,除非索引是“覆盖”,并且在辅助键+主键中找到所需的所有列(对于SELECT
)。
MySQL的MyISAM - MySQL的旧引擎(已经不再使用)将PRIMARY KEY
和辅助密钥实现为BTree,其中叶节点具有到数据文件中的字节地址。因此,这两种类型的密钥都涉及一个BTree潜水加上文件系统“寻找”到另一个文件中。
哈希 - 真正的O(1)查找需要完美的哈希。没有人实现这一点。但是某些实现有一个Hash +某种形式的处理溢出。所以有时候是O(1),有时候慢一点。 (MySQL的MEMORY
引擎上有Hash可用。)
Rownum / Rowid - 这是允许db直接进入行的某种数字。例如,Oracle使用这种东西。但是,您必须先将密钥映射到rownum。所以,这有点是一个两步的过程。 (MySQL不使用Rownum / Rowid。)
一对多 - 在任何情况下,使1:many高效的索引会使索引中的“many”聚集在一起,但可能会有“行” “他们指出分散在数据周围。
Postgresql (我不知道Postgres是如何工作的。)