在MongoDB';中使用阶段之间的投影是否有内存性能优势;什么是聚合管道?
一个集合可能有多个列,每个列包含大量数据,如文章内容或图像数据等 在使用聚合管道阶段时,我假设使用投影减少字段会有好处,因此我们只将所需字段传递给后续阶段,以帮助提高内存使用率 一个简单的例子:我们需要从在MongoDB';中使用阶段之间的投影是否有内存性能优势;什么是聚合管道?,mongodb,Mongodb,一个集合可能有多个列,每个列包含大量数据,如文章内容或图像数据等 在使用聚合管道阶段时,我假设使用投影减少字段会有好处,因此我们只将所需字段传递给后续阶段,以帮助提高内存使用率 一个简单的例子:我们需要从作者集合中查找所有没有匹配作者的文章。我会假设我们不会投射不必要的文章字段。同样的$lookup也适用于作者,我们只需要和id就可以了。演示: db.getCollection("articles").aggregate( [ { $match:
作者
集合中查找所有没有匹配作者的文章
。我会假设我们不会投射不必要的文章字段。同样的$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}
}
}
]
);
我的假设正确吗,还是内部流程的工作方式不同
在使用聚合管道阶段时,我假设
使用投影缩小字段的好处,因此我们只通过
后续阶段的必填字段,以帮助提高内存使用率
是的,这是正确的。每个聚合阶段都有一个内存限制,在该限制内工作将确保不会出现性能问题
从手册()中:
管道级的RAM限制为100 MB。如果是舞台
如果超过此限制,MongoDB将产生错误。考虑到
处理大型数据集时,请使用allowDiskUse
选项启用
将数据写入临时文件的聚合管道阶段
当查询使用allowDiskUse
时,它会影响性能,因为使用磁盘比使用内存慢得多
此外,以下是一些重要的实践:
- 使用尽可能少的阶段;更多阶段意味着文件 需要在每个阶段进行检查。这是额外的处理和维护 资源李>
- 避免不必要的
阶段$project
- 在管道开始时指定某些阶段很重要。阶段,
和$match
只能在初始阶段使用索引。另外,$sort
和$match
如果在管道早期使用,可以减少管道中要处理的文档数量$limit
- 使用
并研究查询计划,以确定是否正在使用索引(在explain
和$match
中)或是否需要为查询优化定义任何索引。请注意,索引与聚合的工作方式略有不同,而且并非所有阶段都可以使用索引$sort
因此,聚合框架可以自动重新安排某些阶段进行优化。有关更多详细信息,请参阅上的本文档。通常,您希望将$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
阶段的场景是解决聚合自身依赖性分析中的缺陷或限制,但应定期避免。谢谢,实际上,我浏览了文档,但错过了“请您更新您的答案以包含该链接以帮助其他用户”部分。再次感谢!这个答案是不正确的,我正在写一个备选答案,但我只是想指出这一点。请参阅我的答案,了解为什么不应包含不必要的额外$project阶段。请注意,100MBs限制仅适用于阻塞阶段(即分组、对完整结果集排序),而不适用于通过管道传递文档的流式阶段。您的投影不是合法语法-您不能混合包含和排除。你实际使用的是哪一个?@AsyaKamsky现场,我输入了一个错误的伪示例。我已经适应了。感谢您,我建议您不要使用“author.0”:{$exists:false}只需使用{“author”:{$ne:[]}按照内部工作方式,执行普通(localField/foreignField)$lookup会更快,而且不用担心$lookup中的$project,而不用切换到更昂贵的表达式$lookup来添加投影。在下一个主要版本之前的所有版本中都是这样的,而且在未来也很可能保持这种状态。我刚刚测试了这个,我的计划不太一样。如果我在第2阶段将$project
留在中,我会得到:{“stages”:[{“$cursor”:{“query”:{“postCode”:{“$ne”:null,“$exists”:true}},,“fields”:{“postCode”:1.0,“_id”:1.0},“queryPlanner”:{
其中包括通常不包括的fields对象。在第2阶段排除$project
,我得到:{“stages”:[{“$cursor”:{“query”:{“postCode”:{“$ne”:null,$exists:true}},“queryPlanner”:{
字段对象缺失的地方。没有$project的示例管道实际上保留了所有字段。因此,没有字段对象被传递到查询子系统。我的使用$group,因此只需要一个字段。这就是为什么我说,如果您确实需要更改应返回的字段,请在最后阶段进行更改。是的,更正它保留了所有字段我想这意味着他们都进入了下一个阶段?我们能把这件事简单地说一下吗