首页 > 解决方案 > $lookup 管道比预期慢

问题描述

我有以下$lookup聚合阶段:

    {
        $lookup: {
            from: "target",
            let: {byTargetId: "$foreignTargetId"},
            pipeline: [
                {
                    $match: {
                        $expr: {
                            $eq: ["$targetId", "$$byTargetId"]
                        }
                    }
                },
                {
                    $project: {
                        someTargetProperty: true
                    }
                }
            ],
            as: "targets"
        }
    }

在我的测试数据库中,在此之前的阶段仅返回 5 个文档。在这种情况下,这些都没有可选属性foreignTargetId,所以我希望byTargetId每次undefined都是这样,并且target集合中的任何文档都不会匹配。

问题是,如果我添加这个查找阶段(最后),聚合需要 1 秒的时间。

target如果我在与查找管道相同的集合上执行此聚合,其undefined值为byTargetId

db.getCollection('target').aggregate(
[
    {
        $match: {
            $expr: {
                $eq: ["$targetId", undefined]
            }
        }
    },
    {
        $project: {
            someTargetProperty: true
        }
    }
])

那么这确实需要大约 200 毫秒,并且 5x200 毫秒 = 1 秒,所以这是有道理的。

null但是,如果我使用以下值执行相同的聚合byTargetId

db.getCollection('target').aggregate(
[
    {
        $match: {
            $expr: {
                $eq: ["$targetId", null]
            }
        }
    },
    {
        $project: {
            someTargetProperty: true
        }
    }
])

然后在 < 1ms 内执行。

  1. null是什么导致和上的相等匹配之间存在如此大的差异undefined
  2. foreignTargetId如果此阶段的输入文档中没有$lookup 阶段,我该如何跳过?

顺便说一句,我在这里使用查找管道的原因是其中的文档target非常大,我只需要someTargetProperty它也在索引中,因此查找可以完全在内存中完成。我注意到在其他情况下,这比查找整个文档并稍后进行投影要快得多。我不会接受试图通过不使用带有管道的 $lookup 来解决此问题的答案。

标签: mongodbmongodb-queryaggregation-framework

解决方案


推荐阅读