我会用聚合框架对一些数据进行分组。观察到当使用$project管道阶段时,它会阻止后续的$match使用索引。我在字段“timestamp”上有一个索引,集合包含500,000条记录。
如果我使用以下命令和管道:
如果我使用以下命令和管道:
db.collection.runCommand('aggregate', {pipeline: [ { "$match" : { "timestamp" : { "$gt" : 1388425361294 , "$lt" : 1388443361294}}} ], explain: true})
执行计划基本符合预期,即扫描了4个文档。摘自“解释”:
"cursor" : {
"cursor" : "BtreeCursor timestamp_1",
"isMultiKey" : false,
"n" : 4,
"nscannedObjects" : 4,
"nscanned" : 4,
"nscannedObjectsAllPlans" : 4,
"nscannedAllPlans" : 4,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"timestamp" : [
[
1388425361294,
1388443361294
]
]
},
.......
但是,一旦使用任何 $project 参数,行为就会发生 drastical 改变。以下命令(即使“country”字段可能不存在于任何文档中,也不会有任何区别):
db.collection.runCommand('aggregate', {pipeline: [ { "$project" : { "country" : "$country"} , { "$match" : { "timestamp" : { "$gt" : 1388425361294 , "$lt" : 1388443361294}}} ], explain: true})
产生这个计划:
"cursor" : {
"cursor" : "BasicCursor",
"isMultiKey" : false,
"n" : 500001,
"nscannedObjects" : 500001,
"nscanned" : 500001,
"nscannedObjectsAllPlans" : 50
"nscannedAllPlans" : 500001,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 101,
"indexBounds" : {
},
很明显,这迫使扫描集合中的所有记录,这对我来说是不可接受的。
在使用 $project 管道阶段时,我是否漏掉了一些重要的东西?