在MongoDB中使用UUID而不是ObjectID

Chr*_*ina 49 mongodb

出于性能原因,我们正在将数据库从MySQL迁移到MongoDB,并考虑将什么用于MongoDB文档的ID.我们正在讨论使用ObjectIDs,它是MongoDB的默认值,还是使用UUID(这是我们在MySQL中一直使用的).到目前为止,我们必须支持以下任何选项的论点如下:

ObjectIDs: ObjectID是MongoDB的默认值,我假设(虽然我不确定)这是有原因的,这意味着我希望MongoDB能够比UUID更有效地处理它们,或者有其他理由选择它们.我还发现这个stackoverflow的答案提到ObjectIDs的使用使得索引更有效率,但是对于这个"更有效"的程度有一些指标会更好.

UUIDs: 我们支持使用UUID的基本论点(并且它是非常重要的)是它们几乎可以通过任何数据库以这种或那种方式得到支持.这意味着如果在某种程度上我们决定从任何原因切换到MongoDB,我们已经有一个API,它根据ID从DB中检索文档,因为ID可以继续,所以这个API的客户端没有任何变化.完全一样.如果我们使用ObjectID,我不确定如何将它们迁移到另一个DB.

有没有人对这些选项中的一个可能比另一个更好以及为什么有任何见解?您是否曾在MongoDB中使用UUID而不是ObjectIDs,如果是,您遇到的优势/问题是什么?

Phi*_*ipp 40

_idMongoDB 的字段可以包含您想要的任何值,只要您可以保证它对于集合是唯一的.当您的数据已经具有自然键时,没有理由不使用它来代替自动生成的ObjectID.

ObjectID作为一个合理的默认解决方案提供给安全时间生成一个自己的唯一密钥(并阻止初学者尝试复制SQL AUTO INCREMENT ,这在分布式数据库中是一个坏主意).

通过不使用ObjectID,您还错过了另一个便利功能:ObjectID在生成时还包含一个unix时间戳,并且许多驱动程序提供了一个提取它并将其转换为日期的功能.这有时会使单独的create-date字段变得多余.

但是当你不关心它时,你可以自由地使用你的UUID作为_id字段.

  • 嗨Christina,实际上MongoDB Java驱动程序中有一张有趣的照片,它显示了在ObjectId和UUID值https://jira.mongodb.org/browse/JAVA-403之间进行比较时的插入时间.很高兴听到你最终采取的方法. (7认同)

Mol*_*mby 12

我认为这是个好主意,Mongo也是如此; 他们将UUID列为_id领域的常见选项之一.

注意事项:

  • 性能 - 正如其他答案所述,基准测试显示UUID会导致插入性能下降.在最糟糕的情况下(从集合中的10M到20M文档),它们的速度要慢大约2-3倍 - 每秒插入2,000(UUID)和7,500(ObjectID)文档之间的差异.这是一个很大的区别,但它的重要性完全取决于你的用例.你会一次批量插入数百万个文档吗?对于大多数应用程序,我构建常见的情况是插入单个文档.在该测试中,差异小得多(6,250 -vs-7,500; ~20%).ID类型根本不是限制因素.
  • 可移植性 - 其他数据库确实倾向于具有良好的UUID支持,因此可以提高可移植性.或者,由于UUID更大(更多位),因此可以将ObjectID重新打包到UUID的"形状"中.这种方法不如直接可移植性好,但它确实为您提供了前进的道路.

与其他一些答案相反:

  • UUID具有本机支持 - 您可以使用Mongo Shell中的UUID()函数,就像使用它一样ObjectID(); 将字符串转换为等效的BSON对象.
  • UUID并不是特别大 - 与96位的ObjectID相比,它们是128位.(它们应使用二进制子类型进行编码0x04.)
  • UUID可以包含时间戳 - 具体来说,UUIDv1对时间戳进行编码,精度为60位,而ObjectID为32位.这超过了6个数量级的精度,因此纳秒秒而不是秒.它实际上可以比Mongo/JS Date对象支持更精确地存储创建时间戳,但是......
    • 内置UUID()函数仅生成v4(随机)UUID,因此,为了利用这一点,您将依靠您的应用程序或Mongo驱动程序来创建ID.
    • 与ObjectID不同,由于UUID被分块的方式,时间戳不会给你一个自然的顺序.根据您的使用情况,这可能是好的也可能是坏的.
    • 在ID中包含时间戳通常是一个坏主意.您最终会在ID暴露的任何地方泄露创建的文档时间.为了使问题更糟,v1 UUID还为其生成的计算机编码唯一标识符,从而可以公开有关基础结构的其他信息(例如,服务器数量).当然,ObjectID也会对时间戳进行编码,因此对于它们来说也是如此.

  • `uuid v4` 更安全,mongodb id 是可预测的并且容易受到记录枚举的影响。 (7认同)

小智 6

考虑每种情况下您将存储的数据量.

MongoDB ObjectID的大小为12个字节,打包用于存储,其部分按性能进行组织(即首先存储时间戳,这是一个逻辑排序标准).

相反,标准UUID是36个字节,包含短划线,通常存储为字符串.此外,即使您删除非数字字符并打算以数字方式存储,您仍必须满足其"indexy"部分(基于时间戳的UUID v1的一部分)位于UUID的中间,并且不会t很适合排序.已完成的研究允许高性能的UUID存储,我甚至编写了一个Node.js库来协助其管理.

如果您打算使用UUID,请考虑重新组织它以获得最佳索引和排序; 否则你可能会遇到性能障碍.

  • 没有理由将 UUID 存储为字符串......标准 UUID 正好是 16 个字节,通常即使在 mongo 中也存储为原始字节。没有人使用 v1 UUID,只有 v4(随机)和 v5(sha1)。 (2认同)
  • 如@Dmitry所述,UUID为16字节(128位),通常不存储为字符串。MongoDB具有本机支持,并将其存储为二进制子类型“ 0x04”。尽管您对不幸的时间戳分块是正确的,但这确实是一个痛苦。我希望有一个更像SQUUID的正式UUID版本。 (2认同)