ChatGPT解决这个技术问题 Extra ChatGPT

我正在尝试确定在 mongo db 中处理复合主键的最佳方法。本系统中与数据交互的主键由 2 个 uuid 组成。 uuid 的组合保证是唯一的,但单个 uuid 都不是。

我看到了几种管理方法:

使用由 2 个值组成的主键对象(如此处建议) 使用标准自动生成的 mongo 对象 id 作为主键,将我的键存储在两个单独的字段中,然后在这两个字段上创建复合索引字段 使主键成为 2 个 uuid 的哈希值 我目前不知道的其他一些很棒的解决方案

这些方法的性能影响是什么?

对于选项 1,由于具有非顺序键,我担心插入性能。我知道这会扼杀传统的 RDBMS 系统,而且我已经看到迹象表明这在 MongoDB 中也是如此。

对于选项 2,拥有一个系统永远不会使用的主键似乎有点奇怪。此外,查询性能似乎不如选项 1。在传统的 RDBMS 中,聚集索引提供了最好的查询结果。这在 MongoDB 中的相关性如何?

对于选项 3,这将创建一个 id 字段,但在插入时它也不会是连续的。这种方法还有其他优点/缺点吗?

对于选项 4,嗯……选项 4 是什么?

此外,还有一些关于将来可能使用 CouchDB 代替 MongoDB 的讨论。使用 CouchDB 会提出不同的解决方案吗?

更多信息:可以找到有关该问题的一些背景here

可能最重要的问题是您将如何访问这些数据?写作显然插入 - 更新?查询呢?删除过吗?
主要是写。然后更新(主要是大爆发)。相当数量的插入(同样,主要是大爆发)。偶尔删除。
更新将使用哪些字段?一个或两个uuid?
更新、删除和查询将针对这两个字段
一起还是单独?或者每个?即每次更新都将针对单个唯一文档(因此提供两个 uuid 值)?

A
Asya Kamsky

你应该选择选项 1。

主要原因是您说您担心性能 - 使用始终存在且已经唯一的 _id 索引将使您不必维护第二个唯一索引。

对于选项 1,我担心插入性能对非顺序键的影响。我知道这会扼杀传统的 RDBMS 系统,而且我已经看到迹象表明这在 MongoDB 中也是如此。

您的其他选项并不能避免这个问题,它们只是将其从 _id 索引转移到辅助唯一索引 - 但现在您有两个索引,一个是右平衡的,另一个是随机访问的。

质疑选项 1 的原因只有一个,那就是您计划仅通过一个或仅通过另一个 UUID 值访问文档。只要您始终提供这两个值并且(这部分非常重要)您始终在所有查询中以相同的方式对它们进行排序,那么 _id 索引将有效地发挥其全部目的。

详细说明为什么您必须确保始终以相同的方式对两个 UUID 值进行排序,当比较子文档 { a:1, b:2 } 不等于 { b:2, a:1 } 时 - 您可能有一个集合,其中两个文档具有这些 _id 值。因此,如果您首先使用字段 a 存储 _id,那么您必须始终在所有文档和查询中保持该顺序。

另一个注意事项是 _id:1 上的索引可用于查询:

db.collection.find({_id:{a:1,b:2}}) 

但它不能用于查询

db.collection.find({"_id.a":1, "_id.b":2})

好的,谢谢,我会记住的。其实是我自己想出来的。 BasicDBObject compositeKey = new BasicDBObject("deviceId", deviceID).append("id", id); String newID = compositeKey.toJson(); 其中 deviceID 和 id 包含我需要附加的值。再次感谢。
至于您提到的第二个注意事项,您是否认为如果我们使用第一个选项(从两个值创建复合 ID),我们是否也应该复制这两个值?因此,我们将获得使用复合 ID 的性能优势,并且还能够查询值。
伙计们,您确定点符号不起作用吗?对我来说确实如此。使用 MongoDB v4.2.6 dropbox.com/s/4z1jgch0lhnqebq/…
哦,查询将起作用,他们只是无法使用 _id 索引。
需要注意的一点是,如果有关主键的某些内容发生更改,选项 1 将来将很难更改。删除和添加新索引比用不同的“_id”重写所有数据要容易得多。
i
i3arnon

我有一个选项 4 给你:

使用自动 _id 字段并为两个 uuid 添加 2 个单字段索引,而不是单个复合索引。

_id 索引将是顺序的(尽管这在 MongoDB 中不太重要),易于分片,您可以让 MongoDB 管理它。 2 个 uuid 索引可让您进行所需的任何类型的查询(第一个、第二个或两者以任何顺序),它们占用的空间比 1 个复合索引少。如果您在同一个查询中同时使用两个索引(以及其他索引),MongoDB 将与它们相交(v2.6 中的新功能),就像您使用复合索引一样。


对顺序索引进行分片是一个坏主意,它不会在所有分片之间均匀共享 + 您将填充无用的索引空间,因为您有 2 个索引而不是 1 个(对大型集合来说很重要)。
@JonathanMuller 如果您使用哈希对它们进行分片,则不会。 “散列键适用于像 ObjectId 这样单调增加的字段”docs.mongodb.org/manual/core/sharding-shard-key/…
B
Boris

我会选择 2 选项,这就是为什么

拥有两个单独的字段,而不是像第 1 条中建议的那样从两个 uuid 连接的一个字段,将使您能够灵活地创建其他索引组合以支持未来的查询请求,或者如果结果证明一个键的基数高于另一个键。具有非顺序键可以帮助您在分片环境中插入时避免热点,所以它不是一个糟糕的选择。在我看来,分片是扩展集合上的插入和更新的最佳方式,因为写锁定是在数据库级别(2.6 之前)或集合级别(2.6 版本)


谢谢,这很有帮助!只是为了澄清一下,您说拥有非顺序键可以帮助使用分片环境。但是,选项 #2 是可以为您提供顺序 ID 的选项。我不明白什么吗?
没错,非顺序键注释与您的问题中的语句有关,您说顺序键在 RDBMS 中很有帮助
在大多数 RDBMS 中,记录物理存储在按主键排序的磁盘上。进行非顺序插入时,必须物理移动所有记录。这就是使用非顺序 ID 使插入变慢的原因。这也是为什么对聚集键的查询如此之快的原因。 (你可能已经知道了,但我只是想把我的问题放在上下文中)。你是说这不是 MongoDB 的情况吗?我的阅读使我相信这仍然是一个考虑因素。我知道标准的 MongoDB ObjectID 是连续的。我认为这是部分原因。
RDBMS 中的聚集索引意味着数据以与索引相同的顺序保存。这需要额外的工作来在“之间”插入数据。在mongo中,没有聚集索引这样的东西,也不需要按照_id索引的顺序将数据添加到磁盘中
啊,这就是我所缺少的。万分感谢!
B
Brent

我会选择选项 2。您仍然可以创建一个同时处理 UUID 字段的索引,并且性能应该与复合主键相同,但使用起来会容易得多。

此外,根据我的经验,我从不后悔给某个东西一个唯一的 ID,即使它不是严格要求的。也许这是一个不受欢迎的意见。


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅