Posted in nosql on 三月 8th, 2011 by kafka0102 mongodb支持的数据类型中,ObjectId是其自有产物,本文对其做些简单的介绍。
存储在mongodb集合中的每个文档(document)都有一个默认的主键_id,这个主键名称是固定的,它可以是mongodb支持的任何数据类 型,默认是ObjectId。在关系数据库schema设计中,主键大多是数值型的,比如常用的int和long,并且更通常的,主键的取值由数据库自增 获得,这种主键数值的有序性有时也表明了某种逻辑。反观mongodb,它在设计之初就定位于分布式存储系统,所以它原生的不支持自增主键。而现实的世界 是,大量应用在可预见的时空里并不需要分布式的mongodb,所以网上就出现了大量的实现mongodb自增主键方法的文章。恩,我之前也干过这种事 情。
还是看看ObjectId的底细吧。ObjectId被设计成跨机器的分布式环境中全局唯一的类型,长度是12个字节。有朋友可能嘀咕了,这可比int大 了两倍,比long也多了一个int,很不经济嘛,但在现在的硬件配置中,多出的这些字节很难有理由成为系统的瓶颈所在,所以尽可能放心使用之。 ObjectId的12字节是如此构成的:0-3这4个字节是时间戳(timestamp)、4-6这3个字节是机器码(machine)、7-8两个字 节是进程id(pid)、9-11是程序自增id(increment)。可以看下java driver中ObjectId的实现代码:
public
class
ObjectId implements
Comparable<
ObjectId>
, java.io
.Serializable
对于ObjectId的组成,有一些值得说道的地方:
1、因为ObjectId以时间戳打头,所以它是近似有序的,使得_id的索引插入效率相比普通索引高很多。
2、ObjectId的前9个字节(timestamp+machine+pid)可以保证不同进程生成的ObjectId不会重复,而后3个字节increment又可以保证同一进程内生成的ObjectId不会重复,所以无需怀疑ObjectId的全局唯一性。
3、ObjectId存储是12个字节,但如果应用有需要以可读的方式表现它,就需要将它转成字符串,这需要24字节(每字节转成2字节的16进制表 示),这个长度的字符串看起来就有些不让人舒服了,如果是追踪某个_id引发的bug,就需要配上copy+paste的杀招。
4、初涉ObjectId的朋友很容易犯的两个错误:1)是查询时直接使用类似db.collection.find({_id:”xx”})式的代码, 结果怎么也查不到明明存在的文档,而正确的写法应该是:db.collection.find({_id:new ObjectId(“xx”)})。2)是集合间有外键关联时,也需要将外键置为ObjectId类型,而不要直接使用上24字节的string。在写与 mongodb打交道的CRUD代码时,需要多留意ObjectId和string的转换代码。
5、ObjectId的产生既可以在应用程序端也可以在mongodb端,各种语言的driver都提供了程序端生成ObjectId的方法,不过大多数 人徒省事直接交给mongodb做了。但从mongodb的设计哲学来说,ObjectId更应该由客户端生成,毕竟应用层比存储层更容易扩展,并会提高 mongodb的插入速度。
原文:http://www.kafka0102.com/2011/03/435.html