我在MongoDB 3.2中做了几个“覆盖查询”测试,并注意到它没有涵盖包含$or
表达式的查询(仅在同一个字段上?)。但是,如果我在同一查询中用$or
表达式替换$in
表达式,它就可以正常工作。
我用于测试的索引如下:
db.test_collection.createIndex({ a: 1, b: 1, c: 1 });
这是$or
查询不的索引
db.test_collection.find({
a: "string",
$or: [
{ b: true },
{ b: false },
],
c: "string"
}, { a: 1, b: 1, c: 1, _id: 0 });
这是 涵盖的$in
查询
db.test_collection.find({
a: "string",
b: { $in: [ true, false ] },
c: "string"
}, { a: 1, b: 1, c: 1, _id: 0 });
字段相同,投影相同。那么,为什么索引不能涵盖$or
查询?
这是explain()
查询的$or
输出:
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.test_collection",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"$or" : [
{
"b" : {
"$eq" : true
}
},
{
"b" : {
"$eq" : false
}
}
]
},
{
"a" : {
"$eq" : "string"
}
},
{
"c" : {
"$eq" : "string"
}
}
]
},
"winningPlan" : {
"stage" : "PROJECTION",
"transformBy" : {
"a" : 1,
"b" : 1,
"c" : 1,
"_id" : 0
},
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"$or" : [
{
"b" : {
"$eq" : true
}
},
{
"b" : {
"$eq" : false
}
}
]
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"a" : 1,
"b" : 1,
"c" : 1
},
"indexName" : "a_1_b_1_c_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"a" : [
"[\"string\", \"string\"]"
],
"b" : [
"[MinKey, MaxKey]"
],
"c" : [
"[\"string\", \"string\"]"
]
}
}
}
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 2,
"executionTimeMillis" : 9,
"totalKeysExamined" : 2,
"totalDocsExamined" : 2,
"executionStages" : {
"stage" : "PROJECTION",
"nReturned" : 2,
"executionTimeMillisEstimate" : 10,
"works" : 3,
"advanced" : 2,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"transformBy" : {
"a" : 1,
"b" : 1,
"c" : 1,
"_id" : 0
},
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"$or" : [
{
"b" : {
"$eq" : true
}
},
{
"b" : {
"$eq" : false
}
}
]
},
"nReturned" : 2,
"executionTimeMillisEstimate" : 10,
"works" : 3,
"advanced" : 2,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 2,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 2,
"executionTimeMillisEstimate" : 10,
"works" : 3,
"advanced" : 2,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"a" : 1,
"b" : 1,
"c" : 1
},
"indexName" : "a_1_b_1_c_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"a" : [
"[\"string\", \"string\"]"
],
"b" : [
"[MinKey, MaxKey]"
],
"c" : [
"[\"string\", \"string\"]"
]
},
"keysExamined" : 2,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
}
},
"serverInfo" : {
"host" : "VM-TOMLIN-HP",
"port" : 27017,
"version" : "3.2.6",
"gitVersion" : "05552b562c7a0b3143a729aaa0838e558dc49b25"
},
"ok" : 1
}
这是explain()
查询的$in
输出:
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.test_collection",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"a" : {
"$eq" : "string"
}
},
{
"c" : {
"$eq" : "string"
}
},
{
"b" : {
"$in" : [
false,
true
]
}
}
]
},
"winningPlan" : {
"stage" : "PROJECTION",
"transformBy" : {
"a" : 1,
"b" : 1,
"c" : 1,
"_id" : 0
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"a" : 1,
"b" : 1,
"c" : 1
},
"indexName" : "a_1_b_1_c_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"a" : [
"[\"string\", \"string\"]"
],
"b" : [
"[false, false]",
"[true, true]"
],
"c" : [
"[\"string\", \"string\"]"
]
}
}
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 2,
"executionTimeMillis" : 0,
"totalKeysExamined" : 2,
"totalDocsExamined" : 0,
"executionStages" : {
"stage" : "PROJECTION",
"nReturned" : 2,
"executionTimeMillisEstimate" : 0,
"works" : 3,
"advanced" : 2,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"transformBy" : {
"a" : 1,
"b" : 1,
"c" : 1,
"_id" : 0
},
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 2,
"executionTimeMillisEstimate" : 0,
"works" : 3,
"advanced" : 2,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"a" : 1,
"b" : 1,
"c" : 1
},
"indexName" : "a_1_b_1_c_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"a" : [
"[\"string\", \"string\"]"
],
"b" : [
"[false, false]",
"[true, true]"
],
"c" : [
"[\"string\", \"string\"]"
]
},
"keysExamined" : 2,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
},
"serverInfo" : {
"host" : "VM-TOMLIN-HP",
"port" : 27017,
"version" : "3.2.6",
"gitVersion" : "05552b562c7a0b3143a729aaa0838e558dc49b25"
},
"ok" : 1
}
答案 0 :(得分:1)
由于 $或运算符的处理方式。根据官方MongoDB课程的video:
$或运算符采用数组,数组包含每个文档 文档被视为单独的查询,$或运算符匹配 任何匹配数组内任何查询的文档等等 它实际上计算了这些查询的并集。
此外,正如documentation所述:
让MongoDB使用索引来评估 $或表达式 索引必须支持 $或表达式中的子句。 否则,MongoDB将执行集合扫描。
如果您将查询重写为以下内容,将使用给定的索引:
db.test_collection.find({
$or: [
{ a: "string", b: true, c: "string"},
{ a: "string", b: false, c: "string" },
],
}, { a: 1, b: 1, c: 1, _id: 0 });
此外,文档直接recommends使用 $ in 运算符来检查相同字段的相等性。