2011-08-30 77 views
3

我有一个包含3种数字性质的化合物_id:MongoDB中复合_id的预期行为?

_id“:{ ”KEYA“:0, ”KEYB“:0, ”KeyC“:0 }

在考虑中的数据库具有用于KEYA和500k的相同的值的2000000倍相同的值集群以KEYB

我的理解是,我可以为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" : {} 

没有限制()的结果是:

"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。有人可以澄清,如果我看到预期的行为,或者我误解了如何使用/查询复合索引?

谢谢, 保罗。

回答

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}

+0

西奥 - 感谢,而你的回答是基本相同mstreams我已经接受你的答案,因为你明确地指出,_id场没有给我一个复合索引(这是我未能把握位) 。我天真地认为,如果我在自动编制索引的_id字段上创建了一个复合键,那么最终结果将是一个复合索引。你生活和学习。 – Paul

8

您需要一个单独的复合索引来表达您所期望的行为。一般来说,我建议不要将对象用作_id,因为键比例在比较中很重要,所以{a:1,b:1}不等于{b:1,a:1}。由于不是所有的驱动程序中的对象保留键顺序也很容易通过做这样的事情来搬起石头砸自己的脚:

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