MongoDB关联查询时,被关联集合的索引能否提升查询性能?
这个问题的答案分两种情况来看:
1. 你当前的聚合写法:B的x索引无法提升性能
先把你的聚合逻辑转换成标准MongoDB语法,大概是这样:
db.A.aggregate([ { $lookup: { from: "B", localField: "bid", foreignField: "_id", as: "b" } }, { $match: { "b.x": "something" } } ])
这个流程的逻辑是:
- 第一步
$lookup:用集合A的bid匹配集合B的_id(B的_id默认有主键索引,这一步会用到这个索引),把所有匹配的B文档关联到A的文档中。 - 第二步
$match:此时关联后的结果已经加载到内存里了,过滤b.x = something是在内存中完成的,根本不会去访问B集合的x索引——相当于先把所有符合_id匹配的B文档都拉过来,再在本地挑x符合条件的,完全用不上B的x索引。
2. 调整聚合写法后:B的x索引可以大幅提升性能
如果把$match的过滤逻辑提前放到$lookup内部的子管道里,就能让MongoDB在关联过程中直接利用B的x索引,减少不必要的数据传输和内存消耗。优化后的写法如下:
db.A.aggregate([ { $lookup: { from: "B", let: { a_bid: "$bid" }, // 把A的bid作为变量传入子管道 pipeline: [ { $match: { $expr: { $eq: ["$_id", "$$a_bid"] }, // 匹配_id和A的bid x: "something" // 提前用x字段过滤B的文档 } } ], as: "b" } }, // 最后过滤掉没有匹配到B文档的结果(可选) { $match: { "b": { $ne: [] } } } ])
这个流程中:
$lookup的子管道里,MongoDB会先利用B的x索引筛选出x = something的文档,再在这些文档里匹配_id = a.bid(同时也会用到_id的主键索引),相当于先缩小B的数据集范围,再做关联,能显著减少需要处理的数据量,这时候B的x索引就完全发挥作用了。
总结
- 原写法:x索引没用,因为过滤是在关联后做内存操作;
- 优化写法:x索引能极大提升性能,因为过滤逻辑被整合到关联阶段,直接利用索引筛选B的数据。
内容的提问来源于stack exchange,提问作者Mars
相关产品推荐
相关产品推荐

