【问题标题】:(How) can aggregate() break an index?(如何)聚合()可以破坏索引?
【发布时间】:2020-01-15 13:59:19
【问题描述】:

(如何)这段代码会破坏 MongoDB 集合上的索引?

db.users.aggregate([
   { $group: { _id: null, total_orders: { $sum: { $size: "$orders" } } } },
])

这是(显然)试图统计所有用户的所有订单。

我继承了一个项目,其中这段代码被注释掉了。我需要取消注释(重新启用)代码,但想了解这样做的风险。此更改的作者不可用,他们注释掉的提交消息是“删除统计调用 - 破坏索引”。

我们使用的 MongoDB 来自 mlab.com,并托管在 AWS 上。我们正在使用 mongoose 从 JS 应用程序连接到 mlab。

【问题讨论】:

    标签: mongodb mongoose mlab


    【解决方案1】:

    我怀疑问题不在于聚合会破坏索引,而是聚合不使用索引并且会执行集合扫描。

    $match and/or $sort stages 放置在管道的开头时,聚合可以利用索引。这个聚合只是一个$group 阶段,这意味着需要遍历整个集合来计算计数。

    我在下面放了一个简单的例子,展示了执行集合扫描的聚合,即使数组字段被索引。

    > db.foo.insert({ "x" : [ 1, 2 ] } )
    > db.foo.insert({ "x" : [ 1 ] } )
    > db.foo.createIndex({ "x" : 1 } )
    ...
    
    > db.foo.aggregate([ { $group: { _id: null, cnt: { $sum : { $size: "$x" } } } } ] )
    { "_id" : null, "cnt" : 3 }
    
    // Results of a .explain() - see 'winningPlan' below
    > db.foo.explain(true).aggregate([ { $group: { _id: null, cnt: { $sum : { $size: "$x" } } } } ] )
    {
        "stages" : [
            {
                "$cursor" : {
                    "query" : {
    
                    },
                    "fields" : {
                        "x" : 1,
                        "_id" : 0
                    },
                    "queryPlanner" : {
                        "plannerVersion" : 1,
                        "namespace" : "stack.foo",
                        "indexFilterSet" : false,
                        "parsedQuery" : {
    
                        },
                        "winningPlan" : {
                            "stage" : "COLLSCAN",
                            "direction" : "forward"
                        },
                        "rejectedPlans" : [ ]
                    },
                    "executionStats" : {
                        "executionSuccess" : true,
                        "nReturned" : 2,
                        "executionTimeMillis" : 0,
                        "totalKeysExamined" : 0,
                        "totalDocsExamined" : 2,
                        "executionStages" : {
                            "stage" : "COLLSCAN",
                            "nReturned" : 2,
                            "executionTimeMillisEstimate" : 0,
                            "works" : 4,
                            "advanced" : 2,
                            "needTime" : 1,
                            "needYield" : 0,
                            "saveState" : 1,
                            "restoreState" : 1,
                            "isEOF" : 1,
                            "invalidates" : 0,
                            "direction" : "forward",
                            "docsExamined" : 2
                        },
                        "allPlansExecution" : [ ]
                    }
                }
            },
            {
                "$group" : {
                    "_id" : {
                        "$const" : null
                    },
                    "cnt" : {
                        "$sum" : {
                            "$size" : [
                                "$x"
                            ]
                        }
                    }
                }
            }
        ],
        "ok" : 1,
        ...
    }
    

    【讨论】:

    • 谢谢,很有可能;我早该想到的!这将得到一位非开发人员同事的支持,他隐约记得统计数据很慢(但我猜提交消息的措辞让我感到困惑)。我会想办法改善这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-02
    • 2016-01-28
    • 1970-01-01
    相关资源
    最近更新 更多