我应该在MongoDB中实现自动递增吗?

问题描述 投票:37回答:5

我正在从MySQL切换到MongoDB。对于一个非常基本的users表,我熟悉的架构将自动递增uidSee Mongo's own documentation for this use case

我想知道这是否是最好的建筑决策。从UX的角度来看,我喜欢将UID作为外部引用,例如在较短的URL中:http://example.com/users/12345

还有第三种方式吗? IRC Freenode的#mongodb中有人建议创建一系列ID并缓存它们。我不确定如何实际实现它,或者是否还有其他路线我可以去。我甚至不一定需要_id本身以这种方式递增。只要users在文档中都有一个独特的数字uid,我会很高兴。

auto-increment uuid mongodb
5个回答
18
投票

Josh,MongoDB中没有自动增量ID,这是有充分理由的。我会说使用在集群中唯一的ObjectIds。

您可以通过序列集合添加自动增量,并使用findAndModify获取要使用的下一个ID。这肯定会给您的应用程序增加复杂性,也可能影响对数据库进行分片的能力。

只要您能保证生成的ID将是唯一的,您就可以了。但头痛将在那里。

您可以在MongoDB的专用Google群组中查看此帖子以获取有关此问题的更多信息:

http://groups.google.com/group/mongodb-user/browse_thread/thread/f57b712b2aae6f0b/b4315285e689b9a7?lnk=gst&q=projapati#b4315285e689b9a7

希望这可以帮助。

谢谢


80
投票

我强烈不同意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

  • 使用10gen's advice
  • 使用mysql作为计数器的存储(如果你担心速度,请看看handlersocket
  • 使用您构建的ID生成服务或使用Twitter等Snowflake之类的服务。

所以这是我对每个人的一般建议。请将您的数据尽可能小。当你长大它会为你节省很多不眠之夜。


15
投票

因此,“自动增量”ID存在根本问题。当你有10个不同的服务器(MongoDB中的分片)时,谁会选择下一个ID?

如果您需要一组自动递增ID,则必须拥有一个用于选择这些ID的权限。在MySQL中,这通常非常简单,因为您只有一台服务器接受写入。但MongoDB的大型部署正在运行分片,而没有这种“中央权威”。

MongoDB使用12字节的ObjectIds,这样每个服务器都可以独立创建新文档,而不依赖于单个权限。

所以这里有一个大问题:“你能负担得起一个权威”吗?

如果是这样,那么你可以使用findAndModify来跟踪“最后一个最高ID”然后你可以插入它。

这是您链接中描述的过程。这里明显的弱点是你在技术上必须为每个插入执行两次写操作。这可能无法很好地扩展,您可能希望在具有高插入率的数据上避免它。它可能适用于用户,它可能无法跟踪点击次数。


7
投票

MongoDB中没有任何类似自动增量的功能,但您可以将自己的计数器存储在专用集合中,并根据需要使用$ inc相关的计数器值。由于$ inc是原子操作,因此您不会看到重复项。


3
投票

默认的Mongo ObjectId(在_id字段中使用的)正在递增。

Mongo使用时间戳(自Unix纪元起的秒数)作为其4-3-2-3组合的第一个4字节部分,与版本1 UUID的组成非常相似(如果不完全相同)。并且在插入时生成ObjectId(如果用户/客户端没有提供其他类型的_id)

因此,ObjectId本质上是序数的;此外,默认排序基于此递增时间戳。

有人可能会认为它是许多dbms中使用的自动递增(index ++)id的更新版本。

© www.soinside.com 2019 - 2024. All rights reserved.