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

ObjectIDs:

UUIDs:

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

推荐答案

在Mongo中使用UUID当然是可能的,并且得到了合理的支持.例如,Mongo文档将UUID列为the _id field的常见选项之一.

考虑因素

  • Performance–正如其他答案所提到的,benchmarks个show UUID会导致插入的性能下降.在最坏的情况下(在一个集合中从benchmarks0万到2000万个文档),它们的速度大约慢了2-3倍——这是每秒插入2000个(UUID)和7500个(ObjectID)文档之间的差异.这是一个很大的区别,但其重要性完全取决于您的用例.你会一次批量插入数百万个文档吗?对于我开发的大多数应用程序,常见的情况是插入单个文档.同样的基准测试显示,对于这种使用模式,差异要小much(6250-vs-7500;~20%).不是无足轻重的..但也不是惊天动地.
  • Portability–许多其他DB平台都有良好的UUID支持,因此可移植性将得到改善.或者,由于UUID更大(更多位),因此有可能达到repack an ObjectID into the "shape" of a UUID.这种方法不如直接可移植性好,但它确实提供了一种在现有objectid和uuid之间"映射"的方法.
  • Decentralisation–UUID的一大卖点是它们具有普遍的独特性.这使得以分散的方式在任何地方生成它们变得切实可行(例如,与自动递增的值不同,自动递增的值需要一个集中的真相来源来确定"下一个"值).当然,Mongo对象ID也承认这一好处.区别在于,UUID基于一个已有15年以上历史的标准,并在(几乎?)上得到支持所有平台、语言等.如果您需要在不连接的系统中创建实体(或者具体地说,related个实体的集合),而不需要与数据库交互,这使得它们非常有用.您可以创建一个带有ID和外键的数据集,然后在将来的某个时候将整个图形写入数据库,而不会产生冲突.虽然这在Mongo ObjectId中也是可能的,但找到生成它们/使用该格式的代码通常会更困难.

更正

与其他一些答案相反:

  • UUIDs do have native Mongo support–您可以使用Mongo Shell中的UUID() function,使用方式与使用ObjectID()完全相同;到convert a UUID string into equivalent BSON object.
  • UUIDs are not especially large–当使用二进制子类型0x04编码时,它们是128位,而ObjectID是96位.(如果将其编码为字符串,将非常浪费,大约需要288位.)
  • UUIDs can include a timestamp–具体来说,UUIDv1以60位的精度对时间戳进行编码,而ObjectID中为32位.这是超过6个数量级的精度,所以nano 秒,而不是秒.它实际上是一种比Mongo/JS日期对象支持的更准确地存储创建时间戳的好方法,但是...

结论

如果孤立地考虑Mongo DB,ObjectId是显而易见的 Select .它们在开箱即用的情况下运行良好,是一个完全有能力的默认值.使用UUIDdoes会增加一些摩擦,无论是在处理值时(需要转换为二进制类型等),还是在性能方面.这个小小的不便是否值得拥有一个标准化的ID格式,实际上取决于您对便携性和架构 Select 的重视程度.

你会在不同的数据库平台之间同步数据吗?您将来会将数据迁移到其他平台吗?您需要在数据库、其他系统或浏览器中生成IDs outside吗?如果不是现在,在future 的某个时刻?UUID可能值得这么麻烦.

八月2021日更新

IEFT最近发布了UUID规范的更新草案,将引入该格式的一些新版本.

具体地说,UUIDv6UUIDv7基于UUIDv1,但翻转时间戳块,以便将位从最高有效位排列到最低有效位.这为结果值提供了一个自然顺序,该顺序(或多或少)反映了它们的创建顺序.新版本还排除了来自服务器MAC地址的数据,解决了对v1 UUID的长期批评.

这些改变需要一段时间才能实现,但(依我看)它们显著地现代化和改进了格式.

Mongodb相关问答推荐

从两个相连的文件中获取电话和邮箱的渠道是什么?

字段$set聚合导致错误美元($)前缀字段$concatArrays对于存储无效"

在提供的文档(_Id)之后和之前,是否有一个Mongo操作来获取已排序(和/或过滤)集合中的文档计数?

为什么这个查询可以在MongoDB中使用?

执行聚合以消除重复并获得唯一计数

在数组对象 Mongodb 中仅 Select 需要的数组

从 Amazon S3(Next.js、Mongodb、Mongoose)删除图像

如何在 MongoDB 中对字段进行自定义排序

在 MongoDB 中加入多个集合

$group 和 sum + 添加所有大于

MongoDB:如何将所有文档合并到聚合管道中的单个文档中

Mongo 可尾游标与 Redis 发布/订阅

在mongodb中实现分页

Mongoose Schema vs Mongo Validator

MongoDB 3 Java判断集合是否存在

如果我在 MongoDB 上使用 LINQ,为什么会失go 性能?

如何在 Rails 中混合使用 mongodb 和传统数据库?

我如何使用 Twitter 的流 api 中的推文并将它们存储在 mongodb 中

使用命令行从 MongoDB 数据库中的所有集合中删除所有索引

我需要手动关闭mongoose连接吗?