首页 > 解决方案 > 提高 MongoDB 上聚合查询的性能

问题描述

我对 mongodb 的聚合框架有一个大问题。我会尽力解释这种情况,但代码很清楚。

我们有一个集合 category 和 notes,每个 note 都有一个 category id 字段和 createdAt 字段,我们希望得到每个类别的最后一个 note。

因此,我们创建了下一个 agreggate 函数:

(async () =>{
        //busco las categorias
        const categoryCollection = db.collection('category');
        const categoryList  = await categoryCollection.find({},{ projection:{name: 1} }).toArray();

        //genero un arrays de ids de categoria
        const categoryIds = categoryList.map(function(e) { 
            return e._id;
        });

        //busco una nota por categoria ordenadas por fecha de creacion de forma descendente
        const articlesColl = db.collection('note');
        const articles = await articlesColl.aggregate([
            { $match: { "category":{$in: categoryIds }}},
            { $sort: { createdAt: -1 }},
            {
                $group: {
                    _id: "$category",
                    note: { $first: "$$ROOT"}
                }
            },
            { $replaceRoot: { newRoot: "$note" } },
            { $project : { _id : 1 ,title : 1, image : 1, category:1} },
            { $skip: skip},
            { $limit : limit }
        ],{allowDiskUse: true}).toArray();

        callback(null, success(
            //reemplazo los category id con el nombre
            articles.map(
                function(doc){
                    doc.categoryName = categoryList.find( e => e._id.equals(doc.category)).name;
                    return doc;
                }
            )
        ));

此查询按每个类别获取最后一个音符,但此“糟糕”的表现。

我使用 mongo atlas,警报向我显示:

查询低效率分数:258393,执行计数 4,平均执行时间 2872 毫秒

这是查询的一个例子。

0: Object $match: Object category: Object $in: Array[23] 0: 5a4536cd920f3a5acdf33a60 1: 5a4536cd920f3a5acdf33a55 2: 5a4536cd920f3a5acdf33a53 3: 5a4536cd920f3a5acdf33a66 4: 5a4536cd920f3a5acdf33a5a 5: 5a4536cd920f3a5acdf33a56 6: 5a4536cd920f3a5acdf33a51 7: 5a4536cd920f3a5acdf33a58 8: 5a4536cd920f3a5acdf33a5b 9: 5a4536cd920f3a5acdf33a57 10: 5a4536cd920f3a5acdf33a63 11: 5a4536cd920f3a5acdf33a5d 12: 5a4536cd920f3a5acdf33a5c 13: 5a4536cd920f3a5acdf33a59 14: 5a4536cd920f3a5acdf33a52 15: 5a4536cd920f3a5acdf33a5e 16: 5a4536cd920f3a5acdf33a65 17: 5a4536cd920f3a5acdf33a61 18: 5b202ef5d03337b3a0227daf 19: 5a4536cd920f3a5acdf33a64 20: 5a4536cd920f3a5acdf33a62 21: 5a4536cd920f3a5acdf33a5f 22: 5a4536cd920f3a5acdf33a54 1: Object $sort: Object createdAt: -1 2: Object $group:对象_id:$category 注意:对象$first:$$ROOT 3:对象$replaceRoot:对象newRoot:$note 4:对象 $project:对象 _id:1 标题:1 图像:1 类别:1 5:对象 $skip:0 6:对象 $limit:8 Fri Aug 17 2018 10:11am 6283 ms 1033573 / 8nScanned / nReturned

这里最大的问题是这个查询真的很慢,有时需要超过 6 秒才能完成。

一些想法来改善这一点?

标签: mongodblambda

解决方案


该查询低效率分数意味着对于您返回的每个文档,查询都会检查 258393 个文档。

您是否考虑过迭代 categoryList 并使用 find 来获取最新的注释?

const articles = categoryList.map(function(e) { 
            return await articlesColl.Find(x => x.category == e._id).Sort({ createdAt: -1 }).Limit(1)
        });

如果您在 {category:1, createdAt:-1} 上创建了一个索引,则运行它只需要检查每个类别的单个文档(在您的示例中总共 23 个)。即使有额外的网络往返,将检查的文档数量减少 100,000 倍应该可以让它们在明显少于 6 秒的时间内完成。


推荐阅读