MongoDB 聚合阶段顺序优化
简易记录
$match + $project
mongoDB会尽可能将 $match 阶段放在 $project 前执行
//原代码
[
{
$project : {
_id : 0, currency : 1,
notional : { $multiply : [ "$price", "$qty" ] }
}
},
{
$match : {
currency : "USD",
notional : { $gt : 1000 }
}
}
]
//mongoDB自动优化后
//由于原集合中文档有currency字段,而notional字段是通过$project阶段生成的,所以拆分为两个$match来运行
[
{
$match : {
currency : "USD"
}
},
{
$project : {
_id : 0, currency : 1,
notional : { $multiply : [ "$price", "$qty" ] }
}
},
{
$match : {
notional : { $gt : 1000 }
}
}
]
$sort + $match
$match 阶段会被放在 $sort阶段之前执行
[
{
$match : {
currency : "USD"
}
},
{
$sort : {
price : 1
}
}
]
$project + $skip
$skip 阶段会被放在 $project 阶段之前运行
[
{
$skip : 2
},
{
$project : {
_id : 0,
currency : 1
}
}
]
$sort + $limit
如果两者之间没有夹杂着会改变文档数量的聚合阶段(如: $match、 $unwind ), $sort 和 $limit 阶段会合并运行来减少文档的输出
//原代码
[
{
$sort : { currency : 1 }
},
{
$project : {
_id : 0,
currency : 1
}
},
{
$limit : 2
}
]
//mongoDB自动优化后(伪代码!!!)
[
{
$sort : { currency : 1 } + $limit : 2
},
{
$project : {
_id : 0,
currency : 1
}
}
]
$limit + $limit
//原代码
{ $limit : 10 },
{ $limit : 5 }
//优化后
{ $limit : 5 }
$skip + $skip
//原代码
{ $skip : 10 },
{ $skip : 5 }
//优化后
{ $skip : 15 }
$match + $match
//原代码
{ $match : { currency : "USD" } },
{ $match : { qty : 1 } }
//优化后
{
$match : {
$and : [
{ currency : "USD" },
{ qty : 1 }
]
}
}
$lookup + $unwind
连续排列在一起的 $lookup 和 $unwind 阶段,如果 $unwind 应用在 $lookup 阶段创建的as字段上,则两者可以合并运行
//原代码
{
$lookup : {
from : "forex",
localField : "currency",
foreignField : "ccy",
as : "forexData"
},
{ $unwind : "$forexData" }
}
//实际执行方案(伪代码!!!)
{
$lookup : {
from : "forex",
localField : "currency",
foreignField : "ccy",
as : "forexData"
}
+
{ $unwind : "$forexData" }
}