聚合管道操作具有优化阶段,该阶段尝试重塑管道以提高性能。
要查看优化器如何转换特定的聚合管道,请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 } }$projectavgTime$project$matchavgTime
该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。