MongoDB的{聚合$match}与{查找find}速度对比

90

我有一个拥有数百万行的 MongoDB 集合,正在尝试优化查询。目前我使用聚合框架检索数据并按照我的要求对其进行分组。我的典型聚合查询类似于: $match > $group > $ group > $project

然而,我注意到前面的部分是最慢的,最后的部分仅需要几毫秒。

我尝试仅使用$match过滤器执行查询,然后使用collection.find执行相同的查询。聚合查询需要约80毫秒,而查找查询需要0或1毫秒。

我几乎在每个字段上都建立了索引,所以我想这不是问题所在。有什么想法会出现什么问题吗?还是聚合框架的“正常”缺点?

我可以使用查找查询代替聚合查询,但我需要在请求之后执行大量处理,并且可以使用$group等快速完成此过程。因此,我宁愿保留聚合框架。

谢谢,

编辑:

以下是我的标准:

{
    "action" : "click",
    "timestamp" : {
            "$gt" : ISODate("2015-01-01T00:00:00Z"),
            "$lt" : ISODate("2015-02-011T00:00:00Z")
    },
    "itemId" : "5"
}

1
你能发布一下你的 $matchfind 吗?在大多数情况下,$matchfind 应该是等价的,但我想看看你正在比较哪些语句,以便给出精确的答案。此外,你是先运行聚合,然后再运行 find 的吗?如果你重复这两个操作并比较时间,会发生什么?差异可能是将结果从磁盘移动到内存的成本。 - wdberkeley
我已经将条件添加到第一篇帖子中,但即使没有时间戳条件,我仍然看到了一个很大的间隔。但现在我想知道这是否与find()返回游标并且仅显示前几个结果有关。 - Antek
13
好的,我有很多无用的索引,所以我清理了所有内容,并创建了一个复合索引(包含我的$match过滤器字段)。现在我的性能很好,并且对于带有$match的查找和聚合操作表现相同 :) 问题解决了。 - Antek
它很可能也严重依赖于MongoDB版本。 - Agoston Horvath
$match和find()在不同的地方是不同的,您无法将限制应用于匹配阶段,必须将其作为不同的阶段完成,这使得它的效率低得多。 - Ethan SK
3个回答

61
聚合框架(aggregation framework)的主要目的是轻松查询大量条目,并生成对您有价值的少量结果。
正如您所说,您也可以使用多个find查询,但请记住,您不能使用find查询创建新字段。另一方面,$group阶段允许您定义新字段。
如果您想实现聚合框架的功能,您很可能需要运行初始find(或链接多个查询),提取该信息,并使用编程语言进一步操作它。 聚合管道(aggregation pipeline)可能看起来需要更长的时间,但至少您知道只需考虑一个系统的性能-MongoDB引擎。
而当涉及到操作从find查询返回的数据时,您很可能需要使用编程语言进一步操纵数据,从而根据所选择的编程语言的复杂性而增加。

68
谢谢提供信息。然而,我仍不明白为什么只有一个 $match 过滤器的聚合查询不如一个简单的查找查询快,虽然它们使用相同的过滤器。 - Antek
@Owumaro,我遇到了与你评论中相同的问题。你找到答案了吗? - zozo
在MongoDB 4.4中,普通查找操作中的投影支持聚合表达式和语法。因此,现在可以使用投影在查找查询中创建新字段。- https://www.mongodb.com/docs/manual/reference/method/db.collection.find/#use-aggregation-expression - Rishabh

15

您尝试过在find查询中使用explain()吗?它会让您对find()查询需要多长时间有一个很好的想法。您也可以使用$ explain来进行$match操作,并查看索引访问和其他参数是否有差异。

此外,聚合框架的$group部分不利用索引,因此必须处理由聚合框架$match阶段返回的所有记录。因此,为了更好地理解查询的工作原理,请查看结果集返回的内容,以及它是否适合在MongoDB中处理。


1
如果您关心性能,那么毫无疑问聚合比查找子句需要更多时间。 当您在多个条件下获取记录时,具有查找、分组和一些有限记录(分页)的查找是最好的方法,同时在查找查询中,当您必须获取非常大的数据集时,它是快速的。如果您有一些人口统计学、投影和没有分页,我建议使用快速的查找查询。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接