将索引与 Mongo 的 $first 组运算符一起使用
Posted
技术标签:
【中文标题】将索引与 Mongo 的 $first 组运算符一起使用【英文标题】:Using an Index with Mongo's $first Group Operator 【发布时间】:2020-04-22 16:11:32 【问题描述】:根据Mongo最新的$group documentation,对$first有一个特别的优化:
优化返回每个组的第一个文档
如果管道按相同字段排序和分组,并且 $group 阶段仅使用 $first 累加器运算符,请考虑在与排序顺序匹配的分组字段上添加索引。在某些情况下,$group 阶段可以使用索引快速找到每个组的第一个文档。
这是有道理的,因为 $group 阶段中的每个 bin 只需要有序索引中的第一个条目。不幸的是,在我的测试中,我得到了一个查询,它在大约 1 秒内呈现约 800k 排序记录,然后将它们传递给 $group,其中大约需要 10 秒来呈现 key
的某些值的 1.7k 输出文档(参见下面的例子)。对于key
的其他值,超时时间为 300 秒。无论key
是什么,组中都应该正好有 1704 个 bin,并且这些查询 bin 应该被索引中的前三个条目覆盖,据我所知。我错过了什么吗?
db.getCollection('time_series').aggregate([
'$match':
'organization_id': 1,
'key': 'waffle_count'
,
'$sort':
'key': 1, 'asset_id': 1, 'date_time': - 1
,
'$group':
'_id':
'key': '$key', 'asset_id': '$asset_id'
,
'value':
'$first': '$value'
]);
这是索引:
"organization_id": 1,
"key": 1,
"asset_id": 1,
"date_time": -1
【问题讨论】:
.explain
说什么?这也取决于你是否有复合索引或单字段索引
很难用可用信息分析您的查询。由于复合索引和索引前缀的性质,“优化以返回每个组的第一个文档”的示例可能不适用于您的情况。因此,即使是文档也表明,“可能是”(我自己的话)。但是,您可以单独尝试以下复合索引,并查看查询以及查询计划的结果是什么:@ 987654328@ 和 "key": 1, "asset_id": 1, "date_time": -1, "value": 1, "organization_id": 1
.
@Ashh,.explain 是我如何知道通过排序的所有内容都在大约 1 秒内运行,从索引返回约 800k 排序条目,并且查询的其余部分在最佳情况下需要 10 秒。
【参考方案1】:
我向 Atlas 的 MongoDB 支持发送了一个请求。我引用的优化直到 4.2 版才可用(我们使用的是 3.6)。引用 Atlas 支持:
您提到的增强功能是在 4.2 中通过 SERVER-9507 实现的。对于您的特定示例,您似乎还需要实现SERVER-40090,以便您的管道充分利用改进。我们会让团队知道它对您的具体情况的潜在好处。
截至目前,第二个问题尚未解决,需要一个简单的 $group _id 设置,例如:
'_id': 'asset_id': '$asset_id'
而指定为对象的键将无法使用索引,即使它不是复合键,如下所示:
'_id': 'asset_id': '$asset_id'
【讨论】:
感谢您让我们知道供应商支持人员告诉您的内容。 快速更新 - 我们更新到 MongoDB 4.2 并且由于这种优化,速度提高了大约 10 倍,即使还没有第二次修复。【参考方案2】:我几乎遇到了类似的情况,我们有一个匹配、排序和分组的管道以相同的顺序。 虽然匹配和排序阶段能够使用索引组,但即使使用 4.2 也不使用索引。 即使在实现https://jira.mongodb.org/browse/SERVER-40090 之后,我也不认为它会允许在组 _id 上使用复合键。 例如
'_id': 'asset_id': '$asset_id'
^^ 将被支持
'_id': 'key': '$key', 'asset_id': '$asset_id'
但是我认为 group 上的复合 _id 不能像上面的示例那样使用索引 ^^
【讨论】:
以上是关于将索引与 Mongo 的 $first 组运算符一起使用的主要内容,如果未能解决你的问题,请参考以下文章
mongo之 前后台创建索引 --noIndexBuildRetry