首页 > 解决方案 > 在 MongoDB 的聚合管道中使用阶段之间的投影是否有内存性能优势?

问题描述

一个集合可能有多个列,每个列都包含大量数据,如文章内容或图像数据等。

在使用聚合管道阶段时,我认为使用投影修剪字段会有好处,因此我们只将所需字段传递到后续阶段以帮助内存使用。

一个简单的例子:我们需要从一个集合中找到所有articles没有匹配作者的人。authors我会假设我们不会再投射不必要的文章字段。与$lookup我们只需要和 id 为此目的的作者相同。演示:

db.getCollection("articles").aggregate(

    [
        {
            $match: {
                somecolumn: { "$ne": null, $exists: true }
            }
        },

        {
            $project: { 
                id: 1,
                authorId: 1
            }
        },

        {
            $lookup: {
                      from: "authors",
                      let: { author: "$authorId" },
                      pipeline: [
                        {
                          $match: {
                              $expr:
                                {
                                    $eq: ["$$author","$id"] }
                              }

                        },
                        { $project: { id: 1, } }
                      ],
                      as: "author"
                    }
        },

        {
            $match: {
                "author.0": {$exists: false}
            }
        }
    ]
);

我的这个假设是正确的,还是内部流程的工作方式不同?

标签: mongodb

解决方案


通常,您唯一希望拥有 $project 的地方是作为最后一个阶段,以便仅将所需的字段返回给客户端,在某些情况下可能会重命名或重新计算它们。

您不需要管道中更早地使用 $project 来“修剪字段”,因为聚合已经进行了依赖性分析并且只获取管道中需要的字段。

这是一个示例,通过以下方式显示explain

db.foo.explain().aggregate({$group:{_id:"$fieldA", count:{$sum:1}}})
{
  "stages" : [
    {
        "$cursor" : {
            "query" : {

            },
            "fields" : {
                "fieldA" : 1,
                "_id" : 0
            },
            "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "snv.foo",
                "indexFilterSet" : false,
                "parsedQuery" : {

                },
                "winningPlan" : {
                    "stage" : "EOF"
                },
                "rejectedPlans" : [ ]
            }
        }
    },
    {
        "$group" : {
            "_id" : "$fieldA",
            "count" : {
                "$sum" : {
                    "$const" : 1
                }
            }
        }
    }
  ]
}

即使我没有投影,您也可以看到只有fieldA返回到管道的其余部分。

唯一需要添加早期$project阶段的场景是解决聚合自身依赖关系分析中的错误或限制,但应常规避免。


推荐阅读