MongoDB性能系列最佳实践-索引

MongoDB

MongoDB中的索引

在任何数据库中,可以用索引支持高效执行查询。如果没有索引,数据库必须扫描集合或表中的每个文档,才能选择与查询语句匹配的文档。如果查询存在适当的索引,数据库可以使用索引来限制必须检查的文档数量,从而提升查询效率。索引的使用可以大大减少查询所需的时间和资源,让数据库能更快速地找到所需数据。因此,在设计数据库时,充分考虑并优化索引的使用,是提升数据库性能的关键一步。

MongoDB提供了丰富的索引类型和功能,并具有针对语言的排序顺序,以支持对数据的复杂访问模式。MongoDB索引可以根据应用程序的需求和查询模式随时创建和删除,并且可以声明在文档中的任何字段上,包括嵌套在数组中的字段。这些灵活的索引功能使得在MongoDB中进行高效的数据访问变得更加简单和便捷。无论是针对特定的字段还是针对文档中的嵌套字段,都可以根据实际需求来创建索引,以提升查询性能和响应时间。通过合理设计和使用索引,可以最大限度地优化MongoDB的性能,提供更好的数据访问体验。

因此,让我们讨论如何在MongoDB中最好地使用索引。

  1. 使用复合索引
    复合索引是由几个不同字段组成的索引。例如,如果您对“姓氏”和“名字”都进行查询,通常最高效的做法是创建包含“姓氏”和“名字”的索引。这样的复合索引不仅可以高效地处理同时指定“姓氏”和“名字”的查询,还可以用于过滤只指定“姓氏”的查询。

  2. 遵循ESR规则
    在设计复合索引时,有一个经验法则有助于确定字段的顺序:根据查询的频率和选择性,将最常用且选择性高的字段放在索引的前面。这样做可以使索引更有效地过滤数据,提高查询的性能:
    在设计复合索引时,以下经验法则可以帮助您确定字段的顺序: 首先,将用于执行等值查询的字段添加到索引中。这些字段通常是经常用于查询条件的字段,例如进行精确匹配的字段。 接下来,考虑对查询结果进行排序的字段。将这些字段添加到索引中,可以使查询在排序时更加高效。
    最后,将需要访问的数据范围的字段添加到索引中。这些字段可以帮助缩小索引的范围,提高查询性能。 通过遵循这个经验法则,您可以设计出更优化的复合索引,以适应不同的查询模式和需求。根据具体情况,按照等值查询字段、排序字段和数据范围字段的顺序,灵活地确定索引字段的排列,以提供更好的查询性能和响应时间。

  3. 在可能的情况下,请尽量使用覆盖查询(Covered Queries)。
    覆盖查询可以直接从索引中返回结果,而无需访问源文档,因此非常高效。 要确定查询是否是覆盖查询,可以使用explain()方法。如果explain()的输出显示totalDocsExamined为0,说明查询是由索引覆盖的。
    在尝试实现覆盖查询时,有一个常见的陷阱是_id字段默认始终返回。您需要明确地将其从查询结果中排除,或者将其添加到索引中。
    在分片集群中,MongoDB内部需要访问分片键的字段。因此,只有在分片键是索引的一部分时,覆盖查询才可行。通常最好将分片键作为索引的一部分。

  4. 在考虑低基数字段上的索引时要小心
    对具有少量唯一值(低基数)的字段进行查询可能会返回大的结果集。复合索引可能包含具有低基数的字段,但合并字段的值应该具有高基数。

  5. 消除不必要的索引
    索引是资源密集型的:即使在MongoDB的WiredTiger存储引擎中使用压缩,它们也会消耗RAM和磁盘。此外,随着字段的更新,相关的索引也必须进行维护,这会增加额外的CPU和磁盘I/O负载。因此,我们应该谨慎评估和删除不再需要的索引。

MongoDB 还提供了工具来帮助您了解索引使用情况:

  1. 通配符索引不能替代基于工作负载的索引规划
    对于具有许多临时查询模式或处理高度多态文档结构的工作负载,通配符索引提供了额外的灵活性。您可以定义一个过滤器,自动为集合中的所有匹配字段、子文档和数组创建索引。
    与任何索引一样,它们也需要存储和维护,因此它们会给数据库增加开销。如果您的应用程序的查询模式事先已知,那么应该使用更有选择性的索引来处理查询访问的特定字段。

  2. 使用文本搜索来匹配字段中的单词
    常规索引用于匹配字段的整个值。如果您只想在包含大量文本的字段中匹配特定单词,则应使用文本索引。 如果您在Atlas服务中运行MongoDB,请考虑使用Atlas全文搜索,它提供了一个与MongoDB数据库集成的完全托管的Lucene索引。全文搜索提供更高的性能和更大的灵活性,用于对数据库进行过滤、排序和排序,以快速呈现与用户最相关的结果。

  3. 使用部分索引
    通过仅包含将通过索引访问的文档来减小索引的大小和性能开销。例如,在orderID字段上创建部分索引,只包括orderStatus为“正在进行中”的订单文档,或者仅在文档中存在emailAddress字段时创建索引。

  4. 利用多键索引查询数组
    如果您的查询模式需要访问单个数组元素,请使用多键索引。MongoDB会为数组中的每个元素创建一个索引键,并且可以构建在持有标量值和嵌套文档的数组上。

  5. 避免未以左锚定或根据的正则表达式
    索引按值排序。前导通配符效率低下,可能导致完整索引扫描。如果表达式中有足够的大小写敏感的前导字符,后置通配符可能是高效的。

  6. 避免大小写不敏感的正则表达式
    如果使用正则表达式的唯一原因是大小写不敏感,请改用大小写不敏感索引,因为它们更快。

  7. 使用WiredTiger存储引擎中提供的索引优化
    如果您自己管理MongoDB,可以将索引放在单独的卷上,从而实现更快的磁盘分页和较低的争用。有关更多信息,请参见WiredTiger选项。

  8. 使用解释计划
    我们在前面的查询模式和性能分析帖子中介绍了使用MongoDB的解释计划,这是检查单个查询的索引覆盖的最佳工具。
    从解释计划中工作,MongoDB提供了可视化工具,以帮助进一步改善您对索引的理解,并提供智能和自动化的建议,可添加哪些索引。

使用MongoDB Compass和Atlas数据浏览器可视化索引覆盖

作为MongoDB的免费GUI,Compass提供许多功能来帮助您优化查询性能,包括探索模式和可视化查询解释计划,这些都是本系列之前介绍过的两个领域。

Compass中的索引选项卡为您的工具库增加了另一个工具。它列出了集合的现有索引,报告索引的名称和键,以及其类型、大小和任何特殊属性。通过索引选项卡,您还可以根据需要添加和删除索引。

使用MongoDB Compass管理索引 图1:使用MongoDB Compass管理索引 一个非常有用的功能是索引使用情况,它显示了索引的使用频率。拥有太多索引可能对性能造成几乎与拥有太少索引一样的破坏性影响,因此这个功能在帮助您识别和删除未使用的索引方面尤其有价值。这有助于释放工作集空间,并消除由于维护索引而产生的数据库开销。

如果您在我们全面托管的Atlas服务中运行MongoDB,则数据浏览器中的索引视图将为您提供与Compass相同的功能,而无需使用单独的工具连接到数据库。

您还可以使用$indexStats聚合管道阶段检索索引统计信息。

自动化索引建议

即使MongoDB的工具提供了所有的遥测信息,您仍然需要负责获取和分析所需的数据,以做出添加哪些索引的决策。

慢查询的阈值根据集群上操作的平均时间而异,以提供与您的工作负载相关的建议。

建议的索引附带有示例查询,根据查询形状(即具有相似谓词结构、排序和投影的查询)分组,这些查询运行在可以受益于添加建议索引的集合上。性能顾问不会对Atlas集群的性能产生负面影响。

如果您对建议满意,可以自动推出新的索引,而无需产生任何应用程序停机时间。

接下来 这就是性能最佳实践系列的最新一篇。MongoDB University提供了一门关于MongoDB性能的免费Web培训课程。这是了解索引的强大之处的好方法。

本系列的下一篇是分片