在我看来,以下两个查询应该具有完全相同的“解释”输出:
查询1:
{
$and: [
{ $or: [
{ Foo: "123" },
{ Bar: "456" }
] },
{ Baz: { $in: ["abc", "def"] } }
]
}
查询2:
{
$or: [
{ Foo: "123" },
{ Bar: "456" }
],
Baz: { $in: ["abc", "def"] } }
}
请注意,我在{ Foo: -1, Baz: -1 }
和{ Bar: -1, Baz: -1 }
上有索引,因此针对$or
运算符进行了优化。事实上,在查询2的版本中,在解释输出中,我看到两个clauses
,两个都有适当的索引边界,一个用于(Foo, Baz)
,一个用于(Bar, Baz)
。 MongoDB正在做它应该做的事情。
但是在第一个版本(查询1)中,不再有clauses
。它给了我一个没有指定索引边界的BasicCursor
。
这两个查询有什么区别?为什么Mongo似乎能够优化#2而不是#1?
现在我正在使用MongoVue测试这些查询,所以我可以控制JSON,但最终我将使用C#驱动程序,我很确定它将始终在#1中发出语法而不是#2,所以找出正在发生的事情很重要......
答案 0 :(得分:4)
这似乎是mongodb中的某种错误。你用的是哪个版本?
根据that bug report,问题已在2.5.3
解决。
在我们转到更高版本(我2.4.6
之前)之前,我们必须小心使用$and
运算符。
我也会在2.6
尝试。
更新:
事实上,我现在已经修复了2.6.3。
> db.test.find()
{ "_id" : 1, "Fields" : { "K1" : 123, "K2" : 456 } }
{ "_id" : 2, "Fields" : { "K1" : 456, "K2" : 123 } }
> db.test.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.test"
},
{
"v" : 1,
"key" : {
"Fields.K1" : 1
},
"name" : "Fields.K1_1",
"ns" : "test.test"
},
{
"v" : 1,
"key" : {
"Fields.K2" : 1
},
"name" : "Fields.K2_1",
"ns" : "test.test"
}
]
> db.test.find({"$and" : [{ "Fields.K1" : 123, "Fields.K2" : 456}]}).explain()
{
"cursor" : "BtreeCursor Fields.K1_1",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 1,
"nscannedObjectsAllPlans" : 2,
"nscannedAllPlans" : 4,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"Fields.K1" : [
[
123,
123
]
]
},
"server" : "benihime:27017",
"filterSet" : false
}
> db.test.find({ "Fields.K1" : 123, "Fields.K2" : 456}).explain()
{
"cursor" : "BtreeCursor Fields.K1_1",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 1,
"nscannedObjectsAllPlans" : 2,
"nscannedAllPlans" : 4,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"Fields.K1" : [
[
123,
123
]
]
},
"server" : "benihime:27017",
"filterSet" : false
}