数据库索引及其 Big-O 表示法

Posted

技术标签:

【中文标题】数据库索引及其 Big-O 表示法【英文标题】:Database indexes and their Big-O notation 【发布时间】:2011-06-09 08:05:35 【问题描述】:

我试图用 Big-O 表示法来理解数据库索引的性能。在不了解的情况下,我猜想:

查询主键或唯一索引将为您提供 O(1) 的查找时间。 查询非唯一索引也会给出 O(1) 时间,尽管“1”可能比唯一索引慢 (?) 对没有索引的列进行查询会产生 O(N) 的查找时间(全表扫描)。

这通常正确吗?查询主键的性能会比 O(1) 更差吗?我特别关心的是 SQLite,但我也想知道这在不同数据库之间的差异程度。

【问题讨论】:

【参考方案1】:

大多数关系数据库将索引构造为 B 树。

如果表有聚簇索引,则数据页存储为 B 树的叶节点。本质上,聚簇索引变成了表。

对于没有聚集索引的表,表的数据页存储在堆中。任何非聚集索引都是 B 树,其中 B 树的叶节点标识堆中的特定页面。

B-tree 的最坏情况高度是 O(log n),由于搜索依赖于高度,B-tree 查找运行在类似(平均而言)

O(logt n)

其中 t 是最小化因子(每个节点必须至少有 t-1 个键和最多 2*t* -1 个键(例如,2*t* 个子节点)。

我是这么理解的。

当然,不同的数据库系统可能在底层使用不同的数据结构。

当然,如果查询不使用索引,那么搜索就是对包含数据页的堆或 B 树的迭代。

如果使用的索引可以满足查询,则搜索会便宜一些;否则,需要后备来获取内存中的相应数据页。

【讨论】:

【参考方案2】:

索引查询(唯一或不唯一)通常为 O(log n)。非常简单,您可以将其视为类似于排序数组中的二进制搜索。更准确地说,它取决于索引类型。但是,例如,b-tree 搜索仍然是 O(log n)。

如果没有索引,那么,是的,是O(N)。

【讨论】:

【参考方案3】:

如果您选择搜索的相同列,则

Primary 或 Unqiue 将为 O(log n):这是一个 b-tree 搜索 非唯一索引也是 O(log n) + 一点:这是一个 b-tree 搜索 无索引 = O(N)

如果您需要来自另一个“来源”(索引交集、书签/键查找等)的信息,因为索引是非覆盖的,那么您可以使用 O(n + log n) 或 O(log n + log n + log n) 因为多次索引命中 + 中间排序。

如果统计数据显示您需要高 % 的行(例如,不是非常有选择性的索引),那么该索引可能会被忽略并变成扫描 = O(n)

【讨论】:

【参考方案4】:

其他答案提供了一个很好的起点;但我只想补充一点,要获得 O(1),主索引本身需要基于哈希(这通常不是默认选择);所以更常见的是对数(B-tree)。

您是正确的,二级索引通常具有相同的复杂性,但实际性能更差——这是因为索引和数据没有聚集,因此常数(磁盘搜索次数)更大。

【讨论】:

【参考方案5】:

这取决于您的查询是什么。

Column = Value 形式的条件允许使用基于散列的索引,其查找时间为 O(1)。但是,many databases, including SQLite, do not support them。 使用关系运算符(<><=>=)的条件可以使用有序索引,通常使用二叉树实现,其查找时间为 O(log n)。 不能使用索引的更复杂的表达式需要 O(n) 时间。

由于您主要对 SQLite 感兴趣,您可能需要阅读它的 Query Optimizer Overview,它更详细地解释了如何选择索引。

【讨论】:

以上是关于数据库索引及其 Big-O 表示法的主要内容,如果未能解决你的问题,请参考以下文章

包含全局最小值的向量的索引

在 mongoDB 中搜索索引数据的复杂度(Big-O)是多少?

主流数据库之索引及其例子

索引及其原理

数据库索引的工作原理及其种类

Lucene-Query的使用及其索引库的维护