【问题标题】:Can a list field be a shard key in MongoDB?列表字段可以是 MongoDB 中的分片键吗?
【发布时间】:2013-05-06 22:48:35
【问题描述】:

有一些看起来像这样的数据:

widget:
{
    categories: ['hair', 'nails', 'dress']
    colors:     ['red', 'white']
}

数据需要这样查询:

SELECT * FROM widget_table WHERE categories == 'hair' AND colors == 'red'

希望将此数据放入 MongoDB 分片集群中。但是,似乎理想的分片键不会是列表字段。在这种情况下,这是不可能的,因为所有字段都是列表字段。

  • 是否可以使用列表字段,例如字段categories作为MongoDB中的分片键?
  • 如果是,我应该注意/注意哪些事项?

非常感谢!

【问题讨论】:

  • 分片键不能是多键,我不确定这是否会很快改变
  • 那么这个数据集是不是用MongoDB不可能分片?
  • 可以对其进行分片,但不能在您列出的两个字段中的任何一个上进行分片,因此要么 _id 要么更改您的架构。无论如何,这对我来说似乎是一个高度可疑的架构
  • @Asya Kamsky - 这可以在列表字段之一上进行分片。该模式不适合分片。但是用例需要它。我意识到我提供的示例对象看起来微不足道,但它被简化以删除不必要的细节。我们正在处理的数据在数千万个对象范围内,需要使用我提供的每分钟数千次的查询进行查询。
  • 这就是我说“或改变你的模式”的原因——这就是你在回答中似乎所做的。这使您的问题是“如何将架构更改为在类别上进行分片”,而不是“如何在数组字段上进行分片”。

标签: mongodb inner-join sharding


【解决方案1】:

根据我得到的一些反馈,似乎断言不可能使用列表字段作为分片键进行分片,我想说明如何使用 MongoDB 的限制对这个用例进行分片:

原始对象:

widget:
{
    primary_key: '2389sdjsdafnlfda'

    categories: ['hair', 'nails', 'dress']
    colors:     ['red', 'white']

    #All the other fields in the document that don't need to be queried upon: 
    ...
    ...
}

数据层根据为分片键选择的字段中元素的数量将对象拆分为多个指针对象:

widget_pointer:
{
    primary_key: '2389sdjsdafnlfda'
    categories: 'hair',
    colors:     ['red', 'white']
}

widget_pointer:
{
    primary_key: '2389sdjsdafnlfda'
    categories: 'nails',
    colors:     ['red', 'white']
}

widget_pointer:
{
    primary_key: '2389sdjsdafnlfda'
    categories: 'dress',
    colors:     ['red', 'white']
}

说明:

  • categories 字段现在可以是 MongoDB 中的分片键。
  • 现在原始对象将存储在键值存储中。查询 MongoDB 中的数据将返回一个指针对象,该对象将用于从键值存储中获取对象。
  • 对 MongoDB 数据的查询只会命中一个分片。
  • 对 MongoDB 数据的插入将命中与列表中的元素一样多的分片,在大多数情况下,只会影响分片总数的一小部分。

【讨论】:

  • 这无关紧要。您所描述的是如何更改您的架构,以便您可以在一个简单的类别字段上进行分片。不能将作为数组(列表)的字段用作分片键。如果您更改架构以使其不再是数组,那么您可以对其进行分片。因为它不是一个列表。
  • 嗨,阿莎。这个例子实际上展示了如何在 MongoDB 的限制下使用用例进行分片。数据层本身充当 MongoDB 之上的另一个数据库层,增加了功能。它使用 MongoDB 来存储索引。最终结果将是数据和索引在多台机器上分片。换句话说,读写只会影响机器的一个子集,向集群添加更多分片会或多或少地线性增加每单位时间对数据执行的操作量。
  • @ChrisDutrow:我同意重构数据不会改变分片键的基本约束(它不能是列表)的评论。当然,您可以将您的对象拆分为列表中每个对象的文档.. 但这对实际的分片实现没有影响。您可以读取一个分片并写入多个分片的唯一方法是复制所有数据。我鼓励您阅读 MongoDB 分片,因为您的解释是错误的。
  • @Stennie - 我不太清楚你的意思,MongoDB 分片键的约束仍然存在。但是,从应用程序的角度来看,原始数据模型的存储和检索受益于分片集群的实现,因为可以实现更高的搜索和写入量,因为搜索和写入操作都是在不影响集群中所有分片的情况下完成的.
  • 如果您将原始对象写入单独的键值对存储,我真的不清楚您如何从将该数据写入 MongoDB 分片集群中受益。我怀疑你实际上想要一个不同的产品来支持你的分片概念...... Redis 或 Cassandra 可能更适合。在数据库之上构建自己的数据库层似乎不是最有效的扩展方法(这就是您首先要进行分片的原因)。
【解决方案2】:

MongoDB 中的分片(如 2.4 版)通过根据 shard key 将文档划分为值范围来工作。列表或数组分片键作为分片键没有意义,因为它包含多个值。

还值得注意的是,分片键是不可变的(一旦为文档设置就无法更改),因此您不想选择要更新的字段。

如果您的文档中没有任何候选字段,您可以随时添加一个。在您的情况下,一个简单的解决方案可能是在 MongoDB 2.4 中使用新的 hashed sharding

您选择作为散列分片键的字段应具有良好的基数或大量不同的值。散列键适用于像 ObjectId 值或时间戳等单调增加的字段。

在分片之前要考虑的一个明显问题是“您需要分片吗?”。分片是一种使用 MongoDB 横向扩展写入的方法,但如果您还没有突破当前配置的限制,则可能会有点矫枉过正。

【讨论】:

  • 我可能错了,但这似乎是错误信息。使用GAE的Big Table,可以对这类数据进行非常大规模的查询。为了做到这一点,数据必须在多台机器上进行分区。在我的脑海中,如果您想使用“类别”作为分片键进行分片,数据库必须在索引中为“类别”列表中的每个值创建一行。如果列表有 4 个元素,但有 1000 个分片,则与搜索的匹配可以缩小到 1000 个分片中的 4 个。
  • 添加散列键不会为指定查询的分片带来任何性能改进,因为查询必须检查所有分片。
  • @ChrisDutrow:您的问题是针对 MongoDB,而不是 BigTable?范围分区绝对是 MongoDB 分片的工作方式,并且您的 shard key 不能包含数组或列表。如果您的 query 匹配四个分片上的文档,那是一个不同的问题。就散列分片键而言:建议只是因为您提到所有字段当前都是数组。 MongoDB中的_id字段不能是数组,因此仍然是候选字段。
  • @ChrisDutrow:有关 MongoDB 分片的介绍,请参阅:Sharding (Tyler Brock, 10gen)。 TL;DR:如果您跳到幻灯片 32(力学)的部分,您将找到分区方法的说明(逻辑 表示一系列文档分片键)。
  • 这个答案不是“错误信息” - 问是否可以做某事(MongoDB 文档明确说不能)然后抱怨解释的答案是相当奇怪的为什么不能这样做是“错误信息”,因为这不是您想听到的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多