MongoDB中复合_id的预期行为?

时间:2011-08-30 16:21:07

标签: mongodb indexing

我有一个包含3个数字属性的复合_id:

_id“:{      “KeyA”:0,      “KeyB”:0,      “KeyC”:0   }

有问题的数据库为KeyA提供了200万个相同的值,为KeyB提供了500k个相同值的集群。

我的理解是我可以使用以下命令高效地查询KeyA和KeyB:

find( { "_id.KeyA" : 1, "_id.KeyB": 3 } ).limit(100)

当我解释这个查询时,结果是:

"cursor" : "BasicCursor",
"nscanned" : 1000100,
"nscannedObjects" : 1000100,
"n" : 100,
"millis" : 1592,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {}

没有limit(),结果是:

"cursor" : "BasicCursor",
"nscanned" : 2000000,
"nscannedObjects" : 2000000,
"n" : 500000,
"millis" : 3181,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {}

据我所知,BasicCursor意味着索引已被忽略,并且两个查询的执行时间都很长 - 即使我只需要100条记录需要大约1.5秒。我打算使用限制来实现分页,但这显然太慢了。

命令:

find( { "_id.KeyA" : 1, "_id.KeyB": 3, , "_id.KeyC": 1000 } )

正确使用BtreeCursor并快速执行建议复合_id是正确的。

我正在使用MongoDb的1.8.3版本。有人可以澄清我是否看到了预期的行为,或者我误解了如何使用/查询复合索引?

谢谢, 保罗。

2 个答案:

答案 0 :(得分:10)

索引不是复合索引,而是_id字段整个值的索引。 MongoDB不会查看索引字段,而是使用字段的原始BSON表示进行比较(如果我正确读取了文档)。

要做你想做的事,你需要一个超过{_id.KeyA: 1, _id.KeyB: 1, _id.KeyC: 1}的实际复合索引(它也应该是一个唯一索引)。由于您不能在_id上建立索引,因此最好将其保留为ObjectId(这将创建更小的索引并浪费更少的空间)并保留KeyAKeyBKeyC字段作为文档的属性。例如。 {_id: ObjectId("xyz..."), KeyA: 1, KeyB: 2, KeyB: 3}

答案 1 :(得分:8)

您需要一个单独的复合索引来表示您想要的行为。一般来说,我建议不要将对象用作_id,因为在比较中键顺序很重要,因此{a:1,b:1}不等于{b:1,a:1}。由于不是所有的驾驶员都保留了物体中的关键顺序,因此通过这样的方式很容易射击自己:

db.foo.save(db.foo.findOne())