我强烈不同意所选答案的作者关于“MongoDB 中没有自动增量 ID 并且有很好的原因”的说法。我们并不知道 10gen 为什么不鼓励使用自动增量 ID,这只是猜测。我认为 10gen 做出这个选择是因为在集群环境中确保 12 字节 ID 的唯一性更加容易。这是默认方案,适用于大多数新手,从而增加了产品采用率,对 10gen 的业务有利。
现在让我来分享一下我在商业环境中使用 ObjectIds 的经验。
我正在构建一个社交网络。我们大约有 6 百万用户,每个用户大约有 20 个好友。
现在想象一下,我们有一个集合,它存储用户之间的关系(谁关注谁)。它看起来像这样
_id : ObjectId
user_id : ObjectId
followee_id : ObjectId
我们拥有一个唯一的复合索引{user_id, followee_id}
。我们可以估计该索引的大小为12*2*6M*20 = 2GB。这是用于快速查找我关注的人的索引。为了快速查找关注我的人,我需要反向索引。那又是另外2GB。
而这仅仅是个开始。我必须随身携带这些ID。我们有一个活动集群,我们在其中存储您的News Feed。那就是您或您的朋友所做的每个事件。想象一下它需要多少空间。
最后,我们的一位工程师做出了一个无意识的决定,并决定将参考文献存储为表示ObjectId的字符串,从而使其大小加倍。
如果一个索引无法适应RAM会发生什么?10gen说:什么好事都没有:
当索引太大无法适应RAM时,MongoDB必须从磁盘读取索引,这比从RAM读取要慢得多。请记住,当服务器具有可用于索引以及其余工作集合的RAM时,索引适合于RAM。
这意味着读取会变慢。锁竞争增加。写入也会变慢。看到80%左右的锁竞争对我来说已经不再震惊。
在你意识到之前,你就会得到一个460GB的集群,你必须将其分割成碎片,并且这很难操作。
Facebook使用64位长作为用户ID :) 这是有原因的。您可以生成顺序ID
所以这是我的一般建议。请尽可能使您的数据尽可能小。当您成长时,它将为您节省许多失眠的夜晚。
_id: {user_id, followee_id}
或者{_id: user_id, followee_id: [array of <followee_id>] }
- Sanfer