我发现,如果索引位于嵌套字段上并且根字段用于查询,则mongodb不会使用索引来完成查询。
// create test collection with index on nested field
> db.test.createIndex({ 'nested.a': 1 })
{
"createdCollectionAutomatically" : true,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
如果仅通过nested
字段进行查询,即使包含索引字段,它也会进行列扫描而不使用索引。
> db.test.find({ nested: { $eq: { a: "" } } }).explain()
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "TestServer.test",
"indexFilterSet" : false,
"parsedQuery" : {
"nested" : {
"$eq" : {
"a" : ""
}
}
},
"winningPlan" : {
"stage" : "COLLSCAN",
"filter" : {
"nested" : {
"$eq" : {
"a" : ""
}
}
},
"direction" : "forward"
},
"rejectedPlans" : [ ]
},
"serverInfo" : {
"host" : "caa1852655c1",
"port" : 27017,
"version" : "3.6.3",
"gitVersion" : "9586e557d54ef70f9ca4b43c26892cd55257e1a5"
},
"ok" : 1
}
我也可以通过显式提供索引字段来解决此问题:
// vvvvvvvvvvvvvv explicitly included
> db.test.find({ 'nested.a': "", nested: { $eq: { a: "" } } }).explain()
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "TestServer.test",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"nested" : {
"$eq" : {
"a" : ""
}
}
},
{
"nested.a" : {
"$eq" : ""
}
}
]
},
"winningPlan" : {
"stage" : "FETCH",
"filter" : {
"nested" : {
"$eq" : {
"a" : ""
}
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"nested.a" : 1
},
"indexName" : "nested.a_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"nested.a" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"nested.a" : [
"[\"\", \"\"]"
]
}
}
},
"rejectedPlans" : [ ]
},
"serverInfo" : {
"host" : "caa1852655c1",
"port" : 27017,
"version" : "3.6.3",
"gitVersion" : "9586e557d54ef70f9ca4b43c26892cd55257e1a5"
},
"ok" : 1
}
但是我质疑为什么这是必须的...在我的实际用例中,嵌套字段不仅包含索引字段,而且还需要完整的相等性检查,但是我宁愿不必在以下情况下显式提供索引字段(我觉得)mongodb应该能够从原始查询中推断出索引。
mongodb无法像我期望的那样推断出正确的索引吗?是否只是由于疏忽而未进行优化?我正在运行3.6.3
版,4.0
或管道中是否有任何改进?还是有更好的方法来处理这种情况?
编辑:我从this question和我自己的实验中发现,它将对$elemMatch
查询使用索引。但是我的顶级字段不是数组,所以我不能使用它。嵌套索引是否始终假设顶级字段是数组?有没有办法让它成为我想要的?