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

Jos*_*ith 40 uuid auto-increment mongodb

我正在从MySQL切换到MongoDB.对于一个非常基本的users表,我熟悉的架构将自动递增uid.有关此用例,请参阅Mongo自己的文档.

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

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

exp*_*ert 82

我强烈不同意MongoDB没有自动增加id的选定答案的作者并且有充分的理由.我们不知道为什么10gen不鼓励使用自动递增的ID.这是猜测.我认为10gen做出了这个选择,因为在集群环境中确保12字节ID的唯一性更容易.它是适合大多数新手的默认解决方案,因此提高了产品的采用率,这对10gen的业务有利.

现在让我告诉大家我在商业环境中使用ObjectIds的经历.

我正在建立社交网络.我们有大约600万用户,每个用户大约有20个朋友.

现在假设我们有一个集合存储用户之间的关系(谁跟谁).看起来像这样

_id : ObjectId
user_id : ObjectId
followee_id : ObjectId
Run Code Online (Sandbox Code Playgroud)

我们有独特的综合指数{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的建议.
  • 使用mysql作为计数器的存储(如果你关心速度看看handlersocket)
  • 使用你建立的ID生成服务或使用像Snowflake by Twitter 这样的东西.

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

  • 万一你想知道,10gen是MongoDB的原始创建者,并且在2013年,[改名为MongoDB Inc.](http://www.mongodb.com/press/10gen-announces-company-name-change- mongodb的-INC) (17认同)

khe*_*eya 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

希望这可以帮助.

谢谢


Gat*_* VP 15

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

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

MongoDB使用12字节,ObjectIds因此每个服务器可以独立创建新文档,而不依赖于单个权限.

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

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

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


小智 9

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

  • 我同意这个答案。即使插入不是原子的,`$inc` 也是原子的。我们可以使用“{new: true}”来获取计数器的新值。例如: `counter.findByIdAndUpdate({_id: counterName}, {$inc: {seq: 1}}, {new: true})` (2认同)

Gab*_*bow 5

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

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

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

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