MongoDB和复合主键

her*_*son 45 primary-key-design mongodb composite-primary-key

我正在尝试确定在mongo db中处理复合主键的最佳方法.与该系统中的数据交互的主要密钥由2个uuids组成.uuids的组合保证是独特的,但是没有个体uuids.

我看到了几种管理方法:

  1. 使用一个对象作为由2个值组成的主键(如此处所示)

  2. 使用标准的自动生成的mongo对象id作为主键,将我的密钥存储在两个单独的字段中,然后在这两个字段上创建一个复合索引

  3. 使主键成为2个uuids的哈希值

  4. 我目前还没有意识到的其他一些很棒的解决方案

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

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

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

对于选项3,这将创建一个单个id字段,但同样在插入时它不会是顺序的.这种方法还有其他优点/缺点吗?

对于选项4,那么......选项4是什么?

此外,还有一些讨论可能在将来的某个时候使用CouchDB而不是MongoDB.使用CouchDB会提出不同的解决方案吗?

更多信息:关于这个问题的一些背景知识可以在这里找到

Asy*_*sky 39

你应该选择1.

主要原因是你说你担心性能 - 使用始终存在的_id索引并且已经唯一将允许你节省必须维护第二个唯一索引.

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

你的其他选择不能避免这个问题,他们只是将它从_id索引转移到辅助唯一索引 - 但现在你有两个索引,一旦是正确平衡的,另一个是随机访问.

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

作为详细解释为什么你必须确保总是以相同的方式对两个UUID值进行排序,当比较子文档{ a:1, b:2 }不等于{ b:2, a:1 }- 你可以有一个集合,其中两个文档具有_id的那些值.因此,如果您首先将_id与字段存储在一起,那么您必须始终在所有文档和查询中保留该顺序.

另一个警告是索引_id:1将可用于查询:

db.collection.find({_id:{a:1,b:2}}) 
Run Code Online (Sandbox Code Playgroud)

但它不能用于查询

db.collection.find({"_id.a":1, "_id.b":2})
Run Code Online (Sandbox Code Playgroud)


Bor*_*ris 6

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

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


i3a*_*non 6

我有一个选项4给你:

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

  1. _id指数是连续的(虽然这在不太重要的MongoDB),容易shardable,你可以让MongoDB管理它.
  2. 2 uuid索引允许您进行所需的任何类型的查询(第一个,第二个或任何顺序),它们占用的空间少于1个复合索引.
  3. 如果您在同一查询中同时使用这两个索引(以及其他索引)MongoDB与它们相交(在v2.6中为new),就像使用复合索引一样.


Bre*_*ent 5

我会选择选项 2。您仍然可以创建一个处理两个 UUID 字段的索引,并且性能应该与复合主键相同,只是它更容易使用。

另外,根据我的经验,我从来没有后悔给某些东西一个唯一的 ID,即使它不是严格要求的。但也许这是一个不受欢迎的观点。