我正在从MySQL切换到MongoDB。对于一个非常基本的users
表,我熟悉的架构会自动递增uid
。 See Mongo's own documentation for this use case
我想知道这是否是最好的架构决策。从UX的角度来看,我喜欢将UID作为外部引用,例如在较短的URL中:http://example.com/users/12345
还有第三种方式吗? IRC Freenode #mongodb
中有人建议创建一系列ID并缓存它们。我不确定如何实际实现它,或者是否还有其他路线我可以去。我甚至不需要_id
本身以这种方式递增。只要users
在文档中都有唯一的数字uid
,我就会很高兴。
答案 0 :(得分:79)
我非常不同意所选答案的作者 MongoDB中没有自动增加ID且有充分理由。我们不知道为什么10gen不鼓励使用自动递增的ID。这是猜测。我认为10gen做出了这个选择,因为在集群环境中确保12字节ID的唯一性更容易。它是适合大多数新手的默认解决方案,因此提高了产品的采用率,这对10gen的业务有利。
现在让我告诉大家我在商业环境中使用ObjectIds的经历。
我正在建立社交网络。我们有大约600万用户,每个用户大约有20个朋友。
现在假设我们有一个存储用户之间关系的集合(谁跟随谁)。看起来像这样
_id : ObjectId
user_id : ObjectId
followee_id : ObjectId
我们有唯一的复合索引{user_id, followee_id}
。我们可以估计该指数的大小为12 * 2 * 6M * 20 = 2GB。现在这是我跟踪的人快速查找的索引。为了快速查找跟随我的人,我需要反向索引。那是另一个2GB。
这只是一个开始。我必须随身携带这些ID。我们有活动集群,用于存储您的新闻Feed。这是你或你的朋友所做的每件事。想象一下它需要多少空间。
最后,我们的一位工程师做出了无意识的决定,并决定将参考文献存储为代表ObjectId的字符串,其大小翻倍。
如果索引不适合RAM,会发生什么?没什么好的,10gen说道。
当索引太大而无法容纳到RAM中时,MongoDB必须从磁盘读取索引,这比从RAM读取要慢得多。请记住,当您的服务器具有可用于索引的RAM以及工作集的其余部分时,索引适合RAM。
这意味着读取速度很慢。锁争用上升。写入速度也会变慢。看到80%的锁定争议对我来说不再是震惊。
在您知道它之前,您最终得到了460GB集群,您必须将其拆分为碎片并且很难操作。
Facebook使用64位长作为用户ID :)这是有原因的。您可以生成顺序ID
所以这是我对每个人的一般建议。请将您的数据尽可能小。当你长大它会为你节省很多不眠之夜。
答案 1 :(得分:18)
乔希, MongoDB中没有自动增量ID,这是有充分理由的。 我会说使用在集群中唯一的ObjectIds。
您可以通过序列集合添加自动增量,并使用findAndModify获取要使用的下一个ID。这肯定会给您的应用程序增加复杂性,也可能影响对数据库进行分片的能力。
只要您能保证生成的ID是唯一的,您就可以了。 但是头痛将会在那里。
您可以在MongoDB的专用Google群组中查看此帖子以获取有关此问题的更多信息:
希望这有帮助。
由于
答案 2 :(得分:15)
因此,“自动增量”ID存在根本问题。如果你有10个不同的服务器(MongoDB中的分片),谁会选择下一个ID?
如果您想要一组自动递增ID,则必须拥有一个用于选择这些ID的权限。在MySQL中,这通常非常简单,因为您只有一台服务器接受写入。但MongoDB的大部署正在运行分片,而没有这种“中央权威”。
MongoDB使用12字节ObjectIds
,这样每个服务器都可以独立创建新文档,而不依赖于单个权限。
所以这是一个大问题:“你能负担得起一个权威”吗?
如果是这样,那么您可以使用findAndModify
来跟踪“最后一个最高ID”,然后您可以插入它。
这是您链接中描述的过程。这里明显的弱点是你在技术上必须为每个插入执行两次写操作。这可能无法很好地扩展,您可能希望在具有高插入率的数据上避免它。它可能适用于用户,它可能无法跟踪点击次数。
答案 3 :(得分:6)
MongoDB中没有任何类似自动增量的功能,但您可以将自己的计数器存储在专用集合中,并根据需要使用$ inc相关的计数器值。由于$ inc是原子操作,因此您不会看到重复项。
答案 4 :(得分:3)
默认的Mongo ObjectId - 在_id字段中使用的 - 正在递增。
Mongo使用时间戳(自Unix纪元以来的秒数)作为其4-3-2-3组合的第一个4字节部分,与版本1 UUID的组成非常相似(如果不完全相同)。并且在插入时生成ObjectId(如果用户/客户端没有提供其他类型的_id)
因此ObjectId本质上是序数的;此外,默认排序基于此递增时间戳。
有人可能会认为它是许多dbms中使用的自动递增(index ++)id的更新版本。