聚合管道操作具有优化阶段,该阶段尝试重塑管道以提高性能。
要查看优化器如何转换特定的聚合管道,请explain
在db.collection.aggregate()
方法中包括该选项
。
优化可能会在版本之间进行更改。
聚合管道可以确定是否仅需要文档中字段的子集即可获得结果。如果是这样,管道将仅使用那些必填字段,从而减少了通过管道的数据量。
$project
或$unset
或$addFields
或$set
)+ $match
序列优化¶对于包含投影阶段($project
或$unset
或
$addFields
或 $set
)后接一个
$match
阶段的聚合管道,MongoDB会将$match
阶段中不需要过滤阶段中计算出的值的所有过滤器移动
到投影$match
之前的新阶段。
如果聚合管道包含多个投影和/或
$match
阶段,则MongoDB将为每个$match
阶段执行此优化
,将每个$match
过滤器移到该过滤器不依赖的所有投影阶段之前。
考虑以下阶段的管道:
优化器将$match
阶段分为四个单独的过滤器,一个用于$match
查询文档中的每个关键字。然后,优化器将每个滤波器移到尽可能多的投影阶段之前,$match
根据需要创建新阶段。给定此示例,优化器将产生以下优化
管道:
该$match
过滤器依赖于
舞台计算领域。该
阶段是此管道中的最后一个投影阶段,因此无法移动打开的滤镜。{ avgTime: { $gt: 7 } }
$project
avgTime
$project
$match
avgTime
该maxTime
和minTime
字段计算的
$addFields
阶段,但对不依赖
$project
阶段。优化$match
器为这些字段上的过滤器创建了一个新
阶段,并将其放置在该$project
阶段之前。
该$match
过滤器不使用在任一所计算的任何值或
所以它被转移到一个新的阶段
都在投影阶段之前的阶段。{ name: "Joe Schmoe" }
$project
$addFields
$match
$sort
+ $match
序列优化¶当您有一个序列$sort
后跟一个时
$match
,请在$match
之前移动,
$sort
以最大程度地减少要排序的对象的数量。例如,如果管道包括以下阶段:
在优化阶段,优化器将序列转换为以下内容:
如果可能,优化阶段将流水线阶段合并到其前身。通常,合并发生在任何序列重新排序优化之后。
$sort
+ $limit
合并¶在版本4.0中更改。
当一个$sort
先于$limit
,优化器可以聚结$limit
到$sort
,如果没有中间阶段的修改文件(例如,使用数$unwind
,$group
)。如果有管道阶段会更改和阶段之间的文档数,则MongoDB将不会合并$limit
到
。$sort
$sort
$limit
例如,如果管道包括以下阶段:
在优化阶段,优化器将序列合并为以下内容:
这样,排序操作就可以仅在执行过程中保持最高n
结果,这n
是指定的限制,而MongoDB仅需要将n
项目存储在内存中
[1]。有关更多信息,请参见$ sort运算符和内存。
用$ skip进行序列优化
如果$skip
在$sort
和$limit
阶段之间有一个阶段,MongoDB将合并
$limit
到该$sort
阶段并增加该
$limit
值$skip
。有关示例,请参见
$ sort + $ skip + $ limit序列。
[1] | 当优化仍将适用
allowDiskUse 是true 与n 项目超过
聚集内存限制。 |
$limit
+ $limit
合并¶当$limit
紧接在另一个之后
$limit
,两个阶段可以合并为一个阶段
$limit
,其中限制量为两个初始限制量中的较小者。例如,管道包含以下序列:
然后第二$limit
阶段可以合并到第一
$limit
阶段并产生一个单一$limit
阶段,其中极限量10
是两个初始极限100
和的最小值10
。
$skip
+ $skip
合并¶当$skip
紧跟另一个$skip
,这两个阶段可合并成一个单一的$skip
,其中跳过量为总和的两个初始跳过量。例如,管道包含以下序列:
然后,第二$skip
阶段可以合并到第一
$skip
阶段,并导致单个$skip
阶段,其中跳过量7
是两个初始限制5
和的总和2
。