我的文档结构如下所示
{
"_id" : "311acd33a0ae8dcc3101246f90af9dc5",
"created_datetime" : ISODate("2013-04-05T10:35:31.143Z"),
"installs" : [
{
"status" : 1,
"app" : "xyz",
"reg_id" : "AVJyaIFI2Q8v93YmOHI5kEOVoCLbd4CAUyVK9zLrC1QCiBcl_bw89i5PvhEuTKmxtb4x130vjMyo78zPI7cedErcRv_Jjn0BN3Wq40hhg",
"last_action_datetime" : ISODate("2013-04-05T10:35:31.143Z"),
"version" : "2"
},
{
"status" : 1,
"app" : "abc",
"reg_id" : "AVJyaIFI2Q8v93YmOHI5kEOVoCLbd4CAUyVK9zLrC1QCiBcl_bw89i5PvhEuTKmxtb4x130vjMyo78zPI7cedErcRv_Jjn0BN3Wq40hhg",
"last_action_datetime" : ISODate("2013-04-05T10:35:31.143Z"),
"version" : "5"
},
{
"status" : 1,
"app" : "pqr",
"last_action_datetime" : ISODate("2013-04-06T10:35:31.143Z"),
"version" : "1"
},
],
"last_update" : ISODate("2013-04-12T06:26:46.333Z"),
"num_updates" : 9,
.....
}
我在'install.reg_id'
和'installs.status'
上有一个复合索引,'installs.status'
上有一个索引
现在我想找到所有文件,其中至少installs
元素包含reg_id
且其status
为1.所以我查询
db.users.find({'installs': {'$elemMatch': {'reg_id': {'$exists': true}, 'status': 1}}}).explain()
我得到了
{
"cursor" : "BtreeCursor installs.status_1",
"isMultiKey" : true,
"n" : 1447034,
"nscannedObjects" : 1720864,
"nscanned" : 1720864,
"nscannedObjectsAllPlans" : 1720864,
"nscannedAllPlans" : 1720864,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 13072,
"nChunkSkips" : 0,
"millis" : 11063,
"indexBounds" : {
"installs.status" : [
[
1,
1
]
]
},
"server" : "####:27017"
}
所以这里应该使用复合索引但是没有使用。我认为$elemMatch
是罪魁祸首所以我做了这个查询
db.users.find({'installs.reg_id': {'$exists': true}}).explain()
我得到了
{
"cursor" : "BasicCursor",
"isMultiKey" : false,
"n" : 2947446,
"nscannedObjects" : 3184871,
"nscanned" : 3184871,
"nscannedObjectsAllPlans" : 3184871,
"nscannedAllPlans" : 3184871,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 23865,
"nChunkSkips" : 0,
"millis" : 16172,
"indexBounds" : {
},
"server" : "####:27017"
}
这表明查询没有使用任何索引。
知道这里出了什么问题吗?
更新:添加提示会使查询使用索引
db.users.find({'installs': {'$elemMatch': {'reg_id': {'$exists': true}, 'status': 1}}}).hint({"installs.reg_id":1,"installs.status":1}).explain()
返回
{
"cursor" : "BtreeCursor installs.reg_id_1_installs.status_1",
"isMultiKey" : true,
"n" : 1451589,
"nscannedObjects" : 2464985,
"nscanned" : 4373261,
"nscannedObjectsAllPlans" : 2464985,
"nscannedAllPlans" : 4373261,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 20170,
"nChunkSkips" : 0,
"millis" : 106353,
"indexBounds" : {
"installs.reg_id" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"installs.status" : [
[
1,
1
]
]
},
"server" : "####:27017"
}
此处使用复合索引。
答案 0 :(得分:3)
没有任何问题。查询优化器正在选择提供更好性能/选择性的索引。
您可以通过“提示”查询使用您希望它使用的索引来确认这一点,并比较需要扫描的元素和文档的数量,以找到它需要返回的内容。
查看您的解释,我可以看到reg_id存在于您希望查询使用的索引中超过92.5%的索引条目。这不是很有选择性。使用您希望它使用的索引仅将3.1M文档/条目缩小到2.9M - 不是很好。
使用status_1索引,它立即将“候选人”缩小到1.7M,现在通过所有这些,它发现1.4M有reg_id。
拥有更多选择性索引是关键,但不要忘记,在这种情况下,您要求它返回1.4M文档,因此当需要扫描这么多文档时,很难非常选择性
另一件事是平等,对于索引(甚至不等于)而言,这比{$ exists}更有效。甚至{$ ne:null}也会比$存在更好 - 通常,依靠使用$ exists或甚至不等式的查询来表示相等性或较小范围的查询(使用索引时)不是一个好主意
可以在此处找到更多信息:http://docs.mongodb.org/manual/applications/indexes/,特别是http://docs.mongodb.org/manual/tutorial/create-queries-that-ensure-selectivity/
答案 1 :(得分:1)
我有同样的问题。它似乎是针对2.7(截止日期:01 / Aug / 14)版本的文档错误: