文档菜单
文档首页
/
MongoDB 手册
/

哈希分片

哈希分片使用单字段哈希索引或一个复合哈希索引作为分片键,在您的分片集群中分区数据。

基于单字段哈希索引的分片

哈希分片以减少定向操作与广播操作的代价,提供了在分片集群中更均匀的数据分布。哈希后,具有“接近”分片键值的文档不太可能位于同一数据块或分片上 - mongos更有可能执行广播操作以完成给定的范围查询。当mongos针对单个分片进行等值匹配查询时。

Diagram of the hashed based segmentation.

哈希索引计算单个字段的哈希值作为索引值;这个值用作您的分片键。[1]

基于复合哈希索引的分片

MongoDB支持创建包含单个哈希字段的复合索引。要创建复合哈希索引,在创建索引时指定任何单个索引键的值为hashed

复合哈希索引计算复合索引中单个字段的哈希值;这个值与其他字段一起用作您的分片键。

复合哈希分片支持诸如区域分片等功能,其中前缀(即第一个)非哈希字段或字段支持区域范围,而哈希字段支持更均匀的分片数据分布。复合哈希分片还支持具有哈希前缀的分片键,以解决与单调递增字段相关的数据分布问题。

提示

MongoDB在解析使用哈希索引的查询时自动计算哈希。应用程序无需计算哈希。

警告

MongoDB的hashed索引在哈希之前将浮点数截断为64位整数。例如,一个hashed索引会存储具有值为2.32.22.9的字段相同的值。为了避免冲突,请不要使用无法可靠转换为64位整数(然后回转为浮点数)的浮点数进行哈希索引。MongoDB的hashed索引不支持大于2的53次方的浮点值。

要查看键的哈希值,请参阅convertShardKeyToHashed()

[1] mongosh提供了convertShardKeyToHashed()方法。此方法使用与哈希索引相同的哈希函数,可以用来查看键的哈希值。

您选择的哈希分片键字段应具有良好的基数,即大量不同的值。哈希键非常适合字段值单调增加的情况,如ObjectId值或时间戳。一个很好的例子是默认的_id字段,假设它只包含ObjectId值。

要使用哈希分片键对集合进行分片,请参阅分片集合。

给定一个使用单调增加值X作为分片键的集合,使用范围分片的结果类似于以下内容

Diagram of poor shard key distribution due to monotonically increasing or decreasing shard key
点击放大

由于X的值始终增加,因此包含MaxKey上限的块接收大多数传入写入。这限制了插入操作仅限于包含此块的单一分片,从而减少了分布式写入在分片集群中的优势。

通过对X使用哈希索引,插入的分布类似于以下内容

Diagram of hashed shard key distribution
点击放大

由于数据现在分布得更均匀,插入在集群中高效分布。

使用sh.shardCollection()方法,指定集合的完整命名空间和用作哈希索引的目标分片键

sh.shardCollection( "database.collection", { <field> : "hashed" } )

要在复合哈希索引上分片集合,指定集合的完整命名空间和用作分片键的复合哈希索引:

sh.shardCollection(
"database.collection",
{ "fieldA" : 1, "fieldB" : 1, "fieldC" : "hashed" }
)

重要

  • 从MongoDB 5.0版本开始,您可以通过更改集合的分片键来重新分片集合。

  • 您可以通过向现有分片键添加后缀字段或字段来细化分片键

如果您使用哈希分片键拆分已填充的集合

  • 分片操作创建一个初始数据块,以覆盖所有分片键值。

  • 在创建初始数据块之后,当需要平衡数据时,均衡器会移动初始数据块的区间。

如果已为集合定义了区域和区域范围,分片集合操作可以对空或不存在集合执行初始数据块创建和分配。初始创建和分配数据块可以加速区域分片设置。初始分配后,均衡器会按照常规管理数据块分配。

在单字段哈希分片键上对空集合进行分片
  • 对于未指定区域和区域范围的空或不存在集合

    • 分片操作创建一个空数据块来覆盖分片键值的整个范围。从版本8.0开始,该操作默认为每个分片创建1个数据块并在集群中迁移。您可以使用numInitialChunks选项指定不同的初始数据块数量并引起初始数据块分配。这种初始创建和分配数据块的操作可以加速分片设置。

    • 初始分配后,均衡器将管理未来的数据块分配。

  • 为空或不存在集合指定了区域和区域范围

    • 分片操作为定义的区域范围创建空数据块,以及覆盖分片键值范围的任何额外数据块,并根据区域范围执行初始数据块分配。这种初始创建和分配数据块的操作可以加速区域分片设置。

    • 初始分配后,均衡器将管理未来的数据块分配。

使用带哈希字段前缀的复合哈希分片键对空集合进行分片

如果复合哈希分片键的哈希字段是前缀(即哈希字段是分片键中的第一个字段)

  • 对于未指定区域和区域范围的空或不存在集合

    • 分片操作创建覆盖分片键值范围的空数据块并执行初始数据块分配。在所有分割点,所有非哈希字段的值都是MinKey。从版本8.0开始,该操作默认为每个分片创建1个数据块并在集群中迁移。您可以使用numInitialChunks选项指定不同的初始数据块数量并引起初始数据块分配。这种初始创建和分配数据块的操作可以加速分片设置。

    • 初始分配后,均衡器将管理未来的数据块分配。

  • 对于指定了从MinKeyMaxKey范围的单个区域,并且为空或不存在集合指定了presplitHashedZones选项,并将其设置为sh.shardCollection():

    • 分片操作为定义的区域范围创建空数据块以及覆盖分片键值范围的任何额外数据块,并根据区域范围执行初始数据块分配。这种初始创建和分配数据块的操作可以加速区域分片设置。

    • 初始分配后,均衡器将管理未来的数据块分配。

在非哈希前缀的复合哈希分片键上对空集合进行分片

如果复合哈希分片键有一个或多个非哈希字段作为前缀(即哈希字段不是分片键中的第一个字段)

  • 如果没有指定空或不存在集合的区域和区域范围,并且preSplitHashedZonesfalse或未指定,MongoDB在分片集合时不会执行任何初始数据块创建或分配。

  • 如果没有指定空或不存在集合的区域和区域范围,并且sh.shardCollection() / shardCollection返回错误。

  • 对于空或不存在集合指定了区域和区域范围,并且指定了preSplitHashedZones选项为sh.shardCollection():

    • 分片操作会为定义的区域范围创建空数据块,以及覆盖所有分片键值范围的任何附加数据块。

    • 分片操作进一步细分每个范围的最初始数据块,使得每个区域内的分片被分配相同数量的数据块。

    • 这种初始数据块的创建和分配使得区域分片设置更快。在初始分配后,平衡器管理后续的数据块分配。

    每个区域定义的范围必须满足某些要求。有关要求和完整示例的说明,请参阅为空或不存在集合预定义区域和区域范围。

从MongoDB 7.0.3(以及6.0.12和5.0.22)开始,您可以删除哈希分片键的索引。

这可以加快使用哈希分片键分片的集合的数据插入速度。它也可以在使用mongosync时加快数据导入速度。

有关详细信息,请参阅删除哈希分片键索引。

提示

另请参阅

要了解如何部署分片集群并实施哈希分片,请参阅部署自管理分片集群。

返回

故障排除分片键