我试图理解为什么Mongo无法在使用$nin
的查询中使用覆盖索引以及如何解决它。我的问题是复合索引,但是它也发生在简单索引上。
制作一个简单的文档:
{b: "text1"}
还有一个简单的索引:
{
"v" : 1,
"key" : {
"b" : 1
},
"name" : "b_1",
"ns" : "mytest"
}
我认为这是一个简单的count()
查询:
db.mytest.count( {b: $nin: [ "foo" ]}, {b:1, _id:0} )
winningPlan
意外包含一个FETCH
:
"winningPlan" : {
"stage" : "COUNT",
"inputStage" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"b" : 1
},
"indexName" : "b_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"b" : [
"[MinKey, \"foo\")",
"(\"foo\", MaxKey]"
]
}
}
}
}
但是在一个简单的相等条件下,它使用COUNT_SCAN
(如预期的那样):
> db.mytest.count( {b: "bar" }, {b:1, _id:0} )
"winningPlan" : {
"stage" : "COUNT",
"inputStage" : {
"stage" : "COUNT_SCAN",
"keyPattern" : {
"b" : 1
},
"indexName" : "b_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1
}
},
为了使事情变得更加有趣,find()
而不是count()
不会查看任何文档:
> db.mytest.find({b:{ $nin: [ 3 ] }}, {b:1, _id:0})
"winningPlan" : {
"stage" : "PROJECTION",
"transformBy" : {
"b" : 1,
"_id" : 0
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"b" : 1
},
"indexName" : "b_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"b" : [
"[MinKey, 3.0)",
"(3.0, MaxKey]"
]
}
}
}
为什么Mongo需要FETCH
与$nin
一起使用?它应该能够完全通过索引来实现。