为啥向数据库字段添加索引会加速对该字段的搜索?

Posted

技术标签:

【中文标题】为啥向数据库字段添加索引会加速对该字段的搜索?【英文标题】:Why does adding an index to a database field speed up searching over that field?为什么向数据库字段添加索引会加速对该字段的搜索? 【发布时间】:2012-09-18 17:31:03 【问题描述】:

我是数据库新手,并且一直在阅读,将索引添加到您需要搜索的字段可以显着加快搜索时间。我理解这个现实,但很好奇它实际上是如何工作的。我已经对该主题进行了一些搜索,但没有找到任何关于其工作原理的好的、简洁且不过度技术性的答案。

我读过它类似于书后的索引,但是对于唯一元素的数据字段(例如用户数据库中的电子邮件地址),使用背面书籍类比将提供与非索引搜索相同的线性查找时间。

这里发生了什么来加快搜索时间?我读过一些关于使用B+-Trees 进行搜索的内容,但描述有点太深入了。我正在寻找的是对正在发生的事情的高级概述,有助于我从概念上理解它,而不是技术细节。

【问题讨论】:

【参考方案1】:

继续你的书后类比,如果页面按该元素排序,则查找时间与非索引搜索相同,是的。

但是,如果您的图书是按作者排序的书评列表,但您只知道 ISBN,该怎么办。 ISBN 是独一无二的,是的,但您仍然需要扫描每条评论才能找到您要查找的评论。

现在,在书的后面添加一个索引,按 ISBN 排序。繁荣,快速的搜索时间。这类似于数据库索引,从索引键 (ISBN) 到实际数据行(在本例中为您的书的页码)。

【讨论】:

这仍然没有提供足够的答案。在表中,事物被存储为字段(列),因此我们可以将数据字段视为一本书中的一章。因此,如果我们转到本书的电子邮件章节,在该处查找电子邮件仍然与在本书索引中查找电子邮件一样快。我们不会扫描整个表格来查找我们想要查找的项目...只是相关字段。 所以您建议为每一章的每一行再次存储 ALL 数据?这样您就有一个“姓氏”章节,按姓氏排序,列出名字、姓氏、出生日期、出生地、用户名、电子邮件和 1000 字的传记。然后你有一个“用户名”章节,按用户名排序,再次列出名字、姓氏、出生日期、出生地、用户名、电子邮件和 1000 字的传记。然后你有一个“电子邮件”章节,按电子邮件排序,列出名字、姓氏、出生日期、出生地、用户名、电子邮件和 1000 字的传记。这似乎是对空间的非常低效的使用...... 好吧,这样想吧。我们有一本书只包含唯一的电子邮件地址(不重复)。就是这样,没有其他内容。在这本书中,如果我们有一个索引,它将是本书内容的精确副本,只是以某种方式排序(尽管取决于制作索引的人)。因此,这种情况下,在书本或索引中搜索电子邮件地址是等效的。这就是为什么我说书籍索引类比失败的原因。显然不止这些,因为索引数据库搜索会比全扫描更快地找到电子邮件。 那是因为它无法知道电子邮件是否有序,直到您将索引放在上面。如果没有索引,它将不得不从头到尾检查每一行。有了索引,它就可以找到它。考虑同一本书的类比,但是,无论它们是否是,您不知道电子邮件是按顺序列出的。你会如何找到你要找的那个?当然,您必须从头开始扫描每一页上的每一行,直到找到它,对吧? 我从未说过电子邮件按任何特定顺序排列。此外,如果你有一个使用书后类比的索引,你仍然需要扫描索引中的每个项目,直到找到你想要找到的值。它仍然是全表扫描......没有收获。我很理解书的类比,但在这里根本行不通。【参考方案2】:

好的,经过一番研究和讨论,以下是我了解到的:

从概念上讲,索引是它所索引的数据字段的排序副本,其中每个索引值都指向它的原始(未排序)行。因为数据库知道值是如何排序的,所以它可以应用更复杂的搜索算法,而不仅仅是从头到尾查找值。 binary search algorithm 是排序列表搜索算法的一个简单示例,它将最大搜索时间从 O(n) 减少到 O(log n)

附带说明:一个体面的排序算法通常需要 O(n log n) 才能完成,这意味着(正如我们之前可能听说过的)你应该只在字段上放置索引您会经常搜索,因为添加索引(包括排序)比进行几次完整搜索要贵一些。例如,在一个包含超过 1,000,000 个条目的大型数据库中,排序的成本是搜索一次的 20 倍。

编辑: 请参阅@Jarod Elliott 的answer 以更深入地了解搜索效率,特别是关于从磁盘操作读取。

【讨论】:

【参考方案3】:

扩展搜索算法的效率,数据库性能的一个关键领域是访问数据的速度。 一般来说,从磁盘读取数据比从内存读取数据要慢很多。

为了说明这一点,让我们假设所有内容都存储在磁盘上。如果您需要在表中的每一行数据中搜索某个字段中的某些值,您仍然需要从磁盘中读取整行数据以查看是否匹配——这通常称为“表扫描” '。

如果您的表是 100MB,那么您需要从磁盘读取 100MB。

如果您现在为要搜索的列建立索引,简单来说,索引将存储数据的每个唯一值以及对相应整行数据的确切位置的引用。与整个表的 100MB 相比,该索引现在可能只有 10MB。

从磁盘读取 10MB 的数据(读取每个匹配的完整行数据可能需要多一点)比读取 100MB 快大约 10 倍。

不同的数据库将以不同的方式将索引或数据存储在内存中,以使这些事情变得更快。但是,如果您的数据集很大并且不适合内存,那么磁盘速度会产生巨大的影响,而索引可以显示出巨大的收益。 在内存中仍然可以有很大的性能提升(以及其他效率)。

一般来说,这就是为什么您可能不会注意到索引一个很容易放入内存的小数据集有任何明显的区别。

底层细节会因系统而异,实际上会复杂得多,但我一直发现磁盘读取与内存读取是一种易于理解的解释方式。

【讨论】:

以上是关于为啥向数据库字段添加索引会加速对该字段的搜索?的主要内容,如果未能解决你的问题,请参考以下文章

sqlserver 在数据查询时是按时间顺序排列的 在时间字段上还有必要加聚集索引吗 为啥

向 Solr 核心添加字段时,为啥会出现“ManagedIndexSchema Error persisting managed schema => FileNotFoundException:

MySQL 索引详解

如何用一款小工具大大加速MySQL SQL语句优化

Elasticsearch:如何使 Elasticsearch 和 Kibana 中的文本字段可聚合?

Elasticsearch:如何使 Elasticsearch 和 Kibana 中的文本字段可聚合?