将索引与 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索引需要注意的几个点

mongo索引

mongo之 前后台创建索引 --noIndexBuildRetry

mongo查询似乎越来越慢

使用 Mongo:我们应该为每种类型的大容量查询创建一个定制的索引吗?

mongo过期索引