【问题标题】:MongoDB-Query OptimizationMongoDB-查询优化
【发布时间】:2015-01-09 12:05:11
【问题描述】:

我有一个包含超过 40K 记录的子文档的集合。 我的聚合查询大约需要 300 秒。我尝试使用复合索引和多键索引来优化相同的内容,这在 180 秒内完成。

我仍然需要减少查询时间的执行。

这是我的收藏:

{
    "_id" : ObjectId("545b32cc7e9b99112e7ddd97"),
    "grp_id" : 654,
    "user_id" : 2,
    "mod_on" : ISODate("2014-11-06T08:35:40.857Z"),
    "crtd_on" : ISODate("2014-11-06T08:35:24.791Z"),
    "uploadTp" : 0,
    "tp" : 1,
    "status" : 3,
    "id_url" : [
     {"mid":"xyz12793"},
     {"mid":"xyz12794"},
     {"mid":"xyz12795"},
     {"mid":"xyz12796"}
    ],
    "incl" : 1,
    "total_cnt" : 25,
    "succ_cnt" : 25,
    "fail_cnt" : 0
}

以下是我的查询

db.member_id_transactions.aggregate([ { '$match':
                           { id_url: { '$elemMatch': { mid: 'xyz12794' } } } },
                           { '$unwind': '$id_url' },
                           { '$match': { grp_id: 654, 'id_url.mid': 'xyz12794' } } ])

有人遇到过同样的问题吗?

这是带有解释选项的聚合查询的 o/p

{
    "result" : [ 
        {
            "_id" : ObjectId("546342467e6d1f4951b56285"),
            "grp_id" : 685,
            "user_id" : 2,
            "mod_on" : ISODate("2014-11-12T11:24:01.336Z"),
            "crtd_on" : ISODate("2014-11-12T11:19:34.682Z"),
            "uploadTp" : 1,
            "tp" : 1,
            "status" : 3,
            "id_url" : [
            {"mid":"xyz12793"},
            {"mid":"xyz12794"},
            {"mid":"xyz12795"},
            {"mid":"xyz12796"}
            ],
            "incl" : 1,
            "__v" : 0,
            "total_cnt" : 21406,
            "succ_cnt" : 21402,
            "fail_cnt" : 4
        }
    ],
    "ok" : 1,
    "$gleStats" : {
        "lastOpTime" : Timestamp(0, 0),
        "electionId" : ObjectId("545c8d37ab9cc679383a1b1b")
    }
}

【问题讨论】:

    标签: node.js performance mongodb mongoose mongodb-query


    【解决方案1】:

    减少被进一步过滤的记录数量的一种方法是在第一个 $match 运算符中包含字段 grp_id

    db.member_id_transactions.aggregate([ 
    {$match:{ "id_url.mid": 'xyz12794',"grp_id": 654 } },
    {$unwind: "$id_url" },
    {$match: { "id_url.mid": "xyz12794" } } 
    ])
    

    看看现在的表现如何。将grp_id 添加到索引以获得更好的响应时间。

    上述聚合查询虽然有效,但不必要。由于您没有更改文档的结构,并且您希望数组中只有一个元素与过滤条件匹配,因此您可以只使用简单的 findproject

    db.member_id_transactions.find(
    { "id_url.mid": "xyz12794","grp_id": 654 },
    {"_id":0,"grp_id":1,"id_url":{$elemMatch:{"mid":"xyz12794"}},
     "user_id":1,"mod_on":1,"crtd_on":1,"uploadTp":1,
     "tp":1,"status":1,"incl":1,"total_cnt":1,
     "succ_cnt":1,"fail_cnt":1
    }
    )
    

    【讨论】:

    • 同意。只是补充。尤其是当您甚至“认为”您需要使用$unwind 时,您“应该”首先尝试将文档过滤到您的“最小”匹配集,但这应该是一般查询规则。澄清第二条语句,当您只希望数组中的“一个”元素与过滤条件匹配时,您不需要聚合,因此不需要 $unwind$elemMatch 在这里也不需要,"id_url.mid": "xyz12794" 会这样做。原理相同,只测试“一个”字段。
    • 很好的解释。已根据您的 cmets 更新了我的答案。(删除了不必要的 $elemMatch 运算符。)
    • 感谢 BatScream 的解决方案...尝试了 find 查询,它就像一个魅力...。非常感谢您节省了我的一天....
    猜你喜欢
    • 2015-01-21
    • 2015-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-13
    • 2021-09-03
    • 2019-10-25
    • 2020-07-05
    相关资源
    最近更新 更多