MongoDB集合中的所有文档都有一个主键,称为_id
。 该字段在插入后自动分配给文档,因此几乎不需要提供它。 _id
字段的有趣之处在于它是基于时间的 。 也就是说,基础类型的_id
,这是ObjectId
,是一个12字节的BSON型 ,和那些字节的4代表秒自Unix纪元。
_id
字段的特殊之处还在于,它会通过在任何集合上调用getIndexes
自动索引,如下所示。
所有MongoDB集合都有一个_id字段作为索引:
> db.things.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "test.things",
"name" : "_id_"
}
]
就像每个人都记得传统RDBMS一样, 索引很重要,因为它们可以使文档检索更快。 但是,索引确实会占用内存,并且在插入文档时会稍微降低性能,因为必须更新所有相应的索引。 因此,尽管您应该认真考虑使用索引,但是在使用索引时需要经济。
自然地,仅当您知道文档的_id
时才方便搜索。 通常会通过其他字段来搜索文档,如果您发现自己是通过时间序列 (例如created_at
进行搜索的,那么您就来了。
想象一下名为logs
的集合,其中包含捕获各种日志消息的简单文档。 示例文档如下所示:
日志收集中的一个简单文档:
{
"_id" : ObjectId("51c4ab6d4d6906d494460728"),
"message" : "crashed, no such method exception",
"type" : "crash",
"created_at" : ISODate("2013-06-21T19:37:17.992Z")
}
如果我想查找某个日期(例如今天)的所有日志消息怎么办? 我可以这样写查询:
查找自2013年6月20日以来创建的所有日志:
db.logs.find({created_at:{'$gt': new Date(2013, 5, 20)}})
如果我对该查询进行解释,则可以看到,因为我在created_at
上没有索引,因此可以利用基本游标,并且扫描了集合中的所有文档以检索结果。
我的发现所附的解释计划:
> db.logs.find({created_at:{'$gt': new Date(2013, 5, 20)}}).explain()
{
"cursor" : "BasicCursor",
"isMultiKey" : false,
"n" : 2,
"nscannedObjects" : 4,
"nscanned" : 4,
"nscannedObjectsAllPlans" : 4,
"nscannedAllPlans" : 4,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
},
"server" : "ghome-computer.home:27017"
}
如您所见,通过created_at
字段进行搜索可能效率不高; 因此,您可能很想在该字段上添加索引。 这自然会使该特定查询效率更高,但是,您将招致新索引的开销,这将消耗更多的内存,并且由于对该新创建的索引进行了更新,因此插入操作会稍微慢一些。
事实证明,由于_id
字段在其中嵌入了Unix纪元,因此无需添加 created_at
字段,您就可以轻松地编写find表达式。 例如, MongoDB Ruby驱动程序允许您从Time
来创建ObjectId
,如下所示:
通过from_time工厂方法创建一个新的ObjectId:
yesterday = Time.now - (60*60*(24*1))
custom_id = BSON::ObjectId.from_time(yesterday)
=> BSON::ObjectId('51c397800000000000000000')
如您所见,我通过from_time
工厂方法创建了一个新的ObjectId
。 51c397800000000000000000是十六进制表示形式,前8位数字表示时间,其他所有内容均清零。
现在,我可以在任何find
表达式中使用我的custom_id
了。 通过Ruby驱动程序,我还可以将一个explain
,which'll展示自由的使用_id
索引。
使用派生日期的ObjectId强制查找使用_id索引:
mongodb[:logs].find({_id: {'$gt' => custom_id}}).explain
=> {"cursor"=>"BtreeCursor _id_", "isMultiKey"=>false, "n"=>1, "nscannedObjects"=>1, "nscanned"=>1, ....}
如果看到BtreeCusor
,则表明您正在使用索引; 如果看到BasicCursor
,那么您知道不是。
因此,如果你发现自己在执行查询和创建了一段时间或日期字段比如索引created_at
,你可能会更好只使用蒙戈的_id
领域,因为它已经嵌入在创建默认情况下,索引的概念。 数字?
翻译自: https://www.javacodegeeks.com/2013/06/mongodb-primary-keys-are-your-friend.html