嘿,我对大型聚合mongo脚本做了一些性能测试,当我将项目行从
"$lookup":{
"from": "metrics",
"as": "metrics",
"let": {"userId": "$_id"},
"pipeline": {
{"$match":{"$expr": {"$in": {"$$userId","$ownerIds"}}}},
----> {"$project": {"fieldName": 1, "ownerIds": 1, "auth0Cache": 1}},
},
},
至
"$lookup":{
"from": "metrics",
"as": "metrics",
"let": {"userId": "$_id"},
"pipeline": {
----> {"$project": {"fieldName": 1, "ownerIds": 1, "auth0Cache": 1}},
{"$match":{"$expr": {"$in": {"$$userId","$ownerIds"}}}},
},
},
它让表演跳起来了。它跑得快2-3倍。当您限制数据时,因为这个集合很大,它应该运行得更快,这是有意义的,但是我没有找到任何关于它的文档。有人知道为什么这是一个重要的变化,并能向我解释为什么会发生,并提供更多的信息吗?提前谢谢。
发布于 2022-10-21 13:26:03
目前问题中的资料太少,无法得出任何明确的结论。作为@Tornike Skhulukhia在评论中建议,共享用于此聚合的完整.explain("executionStats")输出将使我们更清楚地了解可能发生的事情。
基于共享的小部分,这里有一件事情看起来很可疑,那就是使用花括号({和})来定义pipeline。通常,这是一个数组,允许提供一系列的聚合阶段。的确是蒙古操场在使用花括号时会抱怨。在创建问题时,这可能只是一个复制/粘贴错误,特别是因为$in列表中有相同的错误,但当然,如果您使用的驱动程序/语言将pipeline压缩到可能有助于解释正在发生的事情的第一阶段。注意,在某些情况下,可以将单个文档(表示唯一的聚合阶段)传递给.aggregate()方法本身,而不是通常的数组,这里有一个小小的操场示范证明这种结构在那里成功运行。因此,这样的诡计并不是不可能的,更多的信息将是有帮助的。
如果我在代码之间读一点,听起来就像是在努力提高某些聚合管道的性能。尽管没有足够的信息可以肯定地说什么,但我建议简化这个$lookup的定义。现有阶段的定义如下:
{
"$lookup": {
"from": "metrics",
"as": "metrics",
"let": {
"userId": "$_id"
},
"pipeline": [
{
"$match": {
"$expr": {
"$in": [
"$$userId",
"$ownerIds"
]
}
}
},
{
"$project": {
"fieldName": 1,
"ownerIds": 1,
"auth0Cache": 1
}
}
],
}
}这可以简化为使用localField/foreignField语法,至少如下所示:
{
"$lookup": {
"from": "metrics",
"as": "metrics",
localField: "_id",
foreignField: "ownerIds",
"pipeline": [
{
"$project": {
"fieldName": 1,
"ownerIds": 1,
"auth0Cache": 1
}
}
],
}
}此更改可能允许数据库更好地利用metrics集合上的metrics索引。
我要提到的最后一件事是关于$project的使用。的确,一般来说,尽早减少正在处理的数据量是个好主意。但是,投影的使用应该保留在管道(或子管道)的末尾,这只是将结果转换成所需格式的一种方法。数据库将自动计算出管道所需的字段,并尽可能地优化限制数据。
https://stackoverflow.com/questions/74150870
复制相似问题