mongodb - 在 MongoDB 中使用 UUID 而不是 ObjectID

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

对象 ID:
ObjectID 是 MongoDB 的默认值,我假设(虽然我不确定)这是有原因的,这意味着我希望 MongoDB 可以比 UUID 更有效地处理它们,或者有另一个更喜欢它们的原因。我还找到了 this stackoverflow answer提到使用 ObjectID 使索引更有效,但是最好有一些关于这种“更有效”的指标。

UUID:
我们支持使用 UUID(这是一个非常重要的)的基本论点是,它们以一种或另一种方式受到几乎任何数据库的支持。这意味着,如果我们决定从 MongoDB 切换到其他东西,无论出于何种原因,我们已经有一个 API 可以根据它们的 ID 从数据库中检索文档,因此该 API 的客户端没有任何变化,因为 ID 可以继续完全一样。如果我们要使用 ObjectID,我不确定我们将如何将它们迁移到另一个数据库。

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

最佳答案

在 Mongo 中使用 UUID 肯定是可能的,并且得到了相当好的支持。例如,Mongo 文档将 UUID 列为 the _id field 的常用选项之一。 .
注意事项

  • 性能 – 正如其他答案所提到的,benchmarks显示 UUID 会导致插入的性能下降。在测量的最坏情况下(从 10M 到 20M 文档在一个集合中),它们大约慢了大约 2-3 倍——每秒插入 2,000 (UUID) 和 7,500 (ObjectID) 文档之间的差异。这是一个很大的差异,但其重要性完全取决于您的用例。您会一次批量插入数百万个文档吗?对于我构建的大多数应用程序,常见的情况是插入单个文档。相同的基准测试表明,对于该使用模式,差异要小得多(6,250 - 7,500;~20%)。不是微不足道的……但也不是惊天动地的。
  • 便携 – 许多其他数据库平台具有良好的 UUID 支持,因此可移植性将得到改善。或者,由于 UUID 更大(更多位),可以 repack an ObjectID into the "shape" of a UUID .这种方法不如直接可移植性好,但它确实为您提供了一种在现有 ObjectID 和 UUID 之间“映射”的方法。
  • 去中心化 – UUID 的一大卖点是它们普遍独一无二。这使得以去中心化的方式在任何地方生成它们变得切实可行(与例如自动递增值相比,它需要一个集中的事实来源来确定“下一个”值)。当然,Mongo 对象 ID 也证明了这一好处。不同之处在于,UUID 基于 15 年以上的标准并支持(几乎?)所有平台、语言等。如果您需要在脱节的系统,不与数据库交互。您可以创建一个带有 ID 和外键的数据集,然后在将来的某个时间将整个图写入数据库而不会发生冲突。虽然这对于 Mongo ObjectIDs 也是可能的,但是找到生成它们/使用格式的代码通常会更难。

  • 更正
    与其他一些答案相反:
  • UUID 确实有本地 Mongo 支持 – 您可以使用 UUID() function在 Mongo Shell 中使用的方式完全相同 ObjectID() ;至 convert a UUID string into equivalent BSON object .
  • UUID 不是特别大 – 当使用二进制子类型 0x04 编码时它们是 128 位,而 ObjectID 是 96 位。 (如果编码为字符串,它们将非常浪费,占用大约 288 位。)
  • UUID 可以包含时间戳 – 具体而言,UUIDv1 以 60 位精度对时间戳进行编码,而 ObjectID 为 32 位。这是超过 6 个数量级的精度,因此是纳秒而不是秒。它实际上是一种比 Mongo/JS Date 对象支持更准确的存储创建时间戳的好方法,但是......
  • 建于 UUID()函数仅生成 v4(随机)UUID,因此,要利用这一点,您需要依靠您的应用程序或 Mongo 驱动程序来创建 ID。
  • 与 ObjectID 不同,因为 the way UUIDs are chunked ,时间戳不会给你一个自然的顺序。这可能是好是坏,具体取决于您的用例。 (新标准可能会改变这一点;请参阅下面的 2021 年更新。)
  • 在您的 ID 中包含时间戳有时是个坏主意。您最终会在暴露 ID 的任何地方泄露文档的创建时间。 (当然,ObjectID 也对时间戳进行编码,因此这对它们来说也是部分正确的。)
  • 如果您使用(符合规范的)v1 UUID 执行此操作,您还将对服务器 MAC 地址的一部分进行编码,该地址可能用于识别机器。对于大多数系统来说可能不是问题,但也不理想。 (新标准可能会改变这一点;请参阅下面的 2021 年更新。)


  • 结论
    如果您孤立地考虑您的 Mongo DB,那么 ObjectID 是显而易见的选择。它们开箱即用,并且是功能完善的默认设置。使用 UUID 确实会增加一些摩擦,无论是在处理值(需要转换为二进制类型等)时还是在性能方面。这种轻微的不便是否值得拥有标准化的 ID 格式,这实际上取决于您对可移植性和架构选择的重视程度。
    您会在不同的数据库平台之间同步数据吗?您将来会将数据迁移到其他平台吗?您是否需要在数据库外、其他系统或浏览器中生成 ID?如果不是现在在将来的某个时候? UUID 可能值得麻烦。
    2021 年 8 月更新
    IEFT 最近发布了 UUID 规范的更新草案,其中将引入一些新版本的格式。
    具体来说,UUIDv6和 UUIDv7基于 UUIDv1 但翻转时间戳块,因此位从最重要到最不重要排列。这为结果值提供了一个自然顺序(或多或少)反射(reflect)了它们的创建顺序。新版本还排除了从服务器 MAC 地址派生的数据,解决了长期以来对 v1 UUID 的批评。
    这些更改虽然流到实现中需要时间,但(恕我直言)它们显着现代化并改进了格式。

    https://stackoverflow.com/questions/28895067/

    相关文章:

    node.js - Node.js/Mongoose 上的 "VersionError: No ma

    mongodb - 只安装 mongo shell,不安装 mongodb

    node.js - Mongoose 试图打开未关闭的连接

    javascript - MongoDB - 更新集合中所有记录的最快方法是什么?

    mongodb - 尝试连接到 mongodb 服务器时无法识别 mongo 命令

    mongodb - 自动重新连接异常 "master has changed"

    c# - 使用官方 C# 驱动程序在 Mongo DB 中进行更新插入

    javascript - 在 Meteor 应用程序中实现 MongoDB 2.4 的全文搜索

    mongodb - 相当于 MongoDB 的 ERD?

    node.js - Mongoose 密码哈希