Mongodb聚合$group阶段耗时较长

Posted

技术标签:

【中文标题】Mongodb聚合$group阶段耗时较长【英文标题】:Mongodb aggregate $group stage takes a long time 【发布时间】:2019-10-24 23:51:27 【问题描述】:

我正在练习如何使用 MongoDB 聚合,但它们似乎需要很长时间(运行时间)。

每当我使用$group 时,似乎都会发生问题。所有其他查询都运行良好。

我有一些1.3百万虚拟文档需要执行两个基本操作:获取IP地址的计数和唯一 IP 地址。

我的架构看起来像这样:


    "_id":"5da51af103eb566faee6b8b4",
    "ip_address":"...",
    "country":"CL",
    "browser":
        "user_agent":...",
    


运行一个基本的$group 查询平均需要大约12s,这太慢了。

我做了一些研究,有人建议在ip_addresses 上创建一个索引。这似乎减慢了速度,因为查询现在需要13-15s。

我使用 MongoDB,我正在运行的 查询 如下所示:

    visitorsModel.aggregate([
        
            '$group': 
                '_id': '$ip_address',
                'count': 
                    '$sum': 1
                
            
        
    ]).allowDiskUse(true)
        .exec(function (err, docs) 
            if (err) throw err;

            return res.send(
                uniqueCount: docs.length
            )
        )

感谢任何帮助。

编辑:我忘了说,有人说可能是硬件问题?如果有帮助,我将在核心 i5、8GB RAM 笔记本电脑上运行查询。

编辑 2:查询计划:


    "stages" : [
        
            "$cursor" : 
                "query" : 

                ,
                "fields" : 
                    "ip_address" : 1,
                    "_id" : 0
                ,
                "queryPlanner" : 
                    "plannerVersion" : 1,
                    "namespace" : "metrics.visitors",
                    "indexFilterSet" : false,
                    "parsedQuery" : 

                    ,
                    "winningPlan" : 
                        "stage" : "COLLSCAN",
                        "direction" : "forward"
                    ,
                    "rejectedPlans" : [ ]
                ,
                "executionStats" : 
                    "executionSuccess" : true,
                    "nReturned" : 1387324,
                    "executionTimeMillis" : 7671,
                    "totalKeysExamined" : 0,
                    "totalDocsExamined" : 1387324,
                    "executionStages" : 
                        "stage" : "COLLSCAN",
                        "nReturned" : 1387324,
                        "executionTimeMillisEstimate" : 9,
                        "works" : 1387326,
                        "advanced" : 1387324,
                        "needTime" : 1,
                        "needYield" : 0,
                        "saveState" : 10930,
                        "restoreState" : 10930,
                        "isEOF" : 1,
                        "invalidates" : 0,
                        "direction" : "forward",
                        "docsExamined" : 1387324
                    
                
            
        ,
        
            "$group" : 
                "_id" : "$ip_address",
                "count" : 
                    "$sum" : 
                        "$const" : 1
                    
                
            
        
    ],
    "ok" : 1



【问题讨论】:

您查看查询执行统计信息了吗?请分享它们 @AmitPhaltankar 将其添加到原始问题中 查询计划显示 COLLSCAN,查询性能可以受益于索引。集合上是否定义了任何索引? 你能说出你为什么使用allowDiskUseexec吗? 另见:(1) Aggregation, (2) db.collection.aggregate(), $group (aggregation)。 【参考方案1】:

这是有关使用 $group 聚合阶段的一些信息,如果它使用索引,它的局限性以及可以尝试克服这些问题的方法。

1. $group 阶段不使用索引: Mongodb Aggregation: Does $group use index?

2. $group 运算符和内存

$group 阶段的 RAM 限制为 100 兆字节。默认情况下,如果 阶段超过此限制,$group 返回错误。允许 处理大型数据集,将allowDiskUse 选项设置为true。 此标志允许 $group 操作写入临时文件。

见MongoDb docs on $group Operator and Memory

3.使用 $group 和 Count 的示例

一个名为cities的集合:

 "_id" : 1, "city" : "Bangalore", "country" : "India" 
 "_id" : 2, "city" : "New York", "country" : "United States" 
 "_id" : 3, "city" : "Canberra", "country" : "Australia" 
 "_id" : 4, "city" : "Hyderabad", "country" : "India" 
 "_id" : 5, "city" : "Chicago", "country" : "United States" 
 "_id" : 6, "city" : "Amritsar", "country" : "India" 
 "_id" : 7, "city" : "Ankara", "country" : "Turkey" 
 "_id" : 8, "city" : "Sydney", "country" : "Australia" 
 "_id" : 9, "city" : "Srinagar", "country" : "India" 
 "_id" : 10, "city" : "San Francisco", "country" : "United States" 

查询集合以按国家统计城市:

db.cities.aggregate( [
     $group:  _id: "$country", cityCount:  $sum: 1   ,
     $project:  country: "$_id", _id: 0, cityCount: 1  
] )

结果

 "cityCount" : 3, "country" : "United States" 
 "cityCount" : 1, "country" : "Turkey" 
 "cityCount" : 2, "country" : "Australia" 
 "cityCount" : 4, "country" : "India" 

4.使用 allowDiskUse 选项

db.cities.aggregate( [
     $group:  _id: "$country", cityCount:  $sum: 1   ,
     $project:  country: "$_id", _id: 0, cityCount: 1  
],   allowDiskUse : true  )

注意,在这种情况下,它对查询性能或输出没有影响。这只是为了展示用法。

5.一些尝试的选项(建议)

您可以尝试一些方法以获得一些结果(仅供试用):

使用$limit阶段并限制处理的文档数量和 看看结果如何。例如,您可以尝试 $limit: 1000 。 注意这个阶段需要在$group 阶段之前。 您还可以在$group 之前使用$match$project 阶段 阶段来控制输入的shapesize。这可能 返回结果(而不是错误)。


[编辑添加]

Distinct 和 Count 的注意事项:

使用相同的 cities 集合 - 要获取唯一的国家/地区及其计数,您可以尝试使用聚合阶段 $count$group,如以下两个查询所示。

区别:

db.cities.aggregate( [
    $match:  country:  $exists: true   ,
    $group:  _id: "$country"  ,
    $project:  country: "$_id", _id: 0  
] )

结果:

 "country" : "United States" 
 "country" : "Turkey" 
 "country" : "India" 
 "country" : "Australia" 

要将上述结果作为具有唯一值数组的单个文档获取,请使用$addToSetoperator:

db.cities.aggregate( [
    $match:  country:  $exists: true   ,
    $group:  _id: null, uniqueCountries:  $addToSet:  "$country"   ,
    $project:  _id: 0  ,
] )

结果: "uniqueCountries" : [ "United States", "Turkey", "India", "Australia" ]

计数:

db.cities.aggregate( [
    $match:  country:  $exists: true   ,
    $group:  _id: "$country"  ,
    $project:  country: "$_id", _id: 0  ,
    $count: "uniqueCountryCount" 
] )

结果: "uniqueCountryCount" : 4

在上述查询中,$match 阶段用于过滤不存在​​或为空的countryfield 的任何文档。 $project 阶段重塑结果文档。

MongoDB 查询语言:

请注意,当使用 MongoDB 查询语言 命令时,这两个查询会得到相似的结果:db.collection.distinct("country")db.cities.distinct("country").length(注意 distinct 返回一个数组)。

【讨论】:

【参考方案2】:

你可以创建索引

db.collectionname.createIndex(  ip_address: "text"  )

试试这个,它更快。 我想它会对你有所帮助。

【讨论】:

集合已有索引。运行此返回 ..."note" : "all indexes already exist"... 你取的ip_address的数据类型是什么?

以上是关于Mongodb聚合$group阶段耗时较长的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB的聚合操作

mongodb聚合命令

MongoDB聚合操作总结

MongoDB聚合操作总结

MongoDB 聚合比较:group()、$group 和 MapReduce

MongoDB 聚合管道(Aggregation Pipeline)