哈希分片
哈希分片使用单字段哈希索引或 复合哈希索引作为分片键,在分片集群中对数据进行分区。
- 对单字段哈希索引进行分片
哈希分片在分片集群中提供了更均匀的数据分布,但代价是减少了目标操作(相比广播操作)。经过哈希处理后,拥有“接近”分片键值的文档不太可能分布在同一数据段或分片上 -
mongos
更有可能执行广播操作来完成一个给定的范围查询。mongos
可以将等值匹配的查询定位到单个分片。哈希索引会将单个字段的哈希值计算为索引值,而此值将用作分片键。[1]
- 对组合哈希索引进行分片
MongoDB 包含对使用单一哈希字段来创建复合索引的支持。要创建复合哈希索引,请在创建该索引时将
hashed
指定为任一索引键的值。组合哈希索引计算复合索引中单个字段的哈希值;这个值与索引中的其他字段一起用作分片键。
复合哈希分片支持区域分片等功能,其中前缀(即 first)非哈希字段支持区域范围,而哈希字段支持更均匀的分片数据分布。复合哈希分片还支持带有哈希前缀的分片键,用于解决与单调增加字段相关的数据分布问题。
提示
在使用哈希索引解析查询时,MongoDB 会自动计算哈希值。应用程序无需计算哈希值。
警告
MongoDB hashed
索引会在行哈希运算之前将浮点数截断为 64 位整数。例如,hashed
索引将为包含值 2.3
、2.2
和 2.9
的字段存储相同的值。为防止冲突,请勿对无法可靠转换为 64 位整数(然后再转换回浮点数)的浮点数使用 hashed
索引。MongoDB hashed
索引不支持大于 2 的浮点值 53 。
要查看某个键的哈希值,请参阅 convertShardKeyToHashed()
。
[1] | mongosh 提供 convertShardKeyToHashed() 方法。此方法使用与哈希索引相同的哈希函数,且可用于查看某一键的哈希值。 |
哈希分片键
您选择作为哈希分片键的字段应具有良好的关联基数数或大量不同的值。哈希键非常适合具有像对象标识符值或时间戳这样单调变化字段的分片键。默认的 _id
字段便是个很好的例子,假设它只包含对象标识符值。
要使用哈希分片键对集合进行分片,请参阅对集合进行分片。
哈希和范围分片
给定一个使用单调递增值 X
作为分片键的集合,使用范围分片后,传入的插入值的分布类似如下:
由于X
的值始终在增加,因此具有maxKey上限的数据块会接收大多数传入写入。这会将插入操作限制为包含此数据块的单个分片,从而减少或消除了分片集群中分布式写入的优势。
在 X
上使用哈希索引后,插入值的分布类似如下:
由于数据现在更均匀地分布,因此可以高效地将插入操作分布在整个集群中。
将集合分片
使用 sh.shardCollection()
方法,指定集合的完整命名空间和用作分片键的目标哈希索引。
sh.shardCollection( "database.collection", { <field> : "hashed" } )
要在复合哈希索引上对集合进行分片,请指定集合的完整命名空间和用作分片键的目标复合哈希索引:
sh.shardCollection( "database.collection", { "fieldA" : 1, "fieldB" : 1, "fieldC" : "hashed" } )
对填充的集合进行分片
如果使用哈希分片键对已填充的集合进行分片:
分片操作会创建初始数据块以覆盖分片键值的整个范围。创建的数据块数量取决于配置的数据块大小。
在创建初始数据块后,负载均衡器会根据需要在分片之间迁移这些初始数据块,并托管未来的数据块分布。
对空集合进行分片
分片集合操作可以对空集合或不存在的集合执行初始数据块创建和分发,前提是已为该集合定义区域和区域范围。数据段的初始创建和分布可以更快地设置区域分片。在初始分布之后,负载均衡器将照例管理未来的数据块分布。
- 使用单字段哈希分片键对空集合进行分片
没有为空集合或不存在的集合指定区域和区域范围:
分片操作创建空数据段以覆盖分片键值的整个范围,并执行初始数据段分布。默认情况下,该操作为每个分片创建 2 个数据段,并在集群中迁移。您可以使用
numInitialChunks
选项来指定其他数量的初始数据段。数据段的初始创建和分布可以更快设置分片。在初始分布之后,负载均衡器将管理未来的数据段分布。
对于空的或不存在的collection指定了区域和区域范围(从 MongoDB 4.0.3 开始可用):
分片操作为定义的区域范围创建空数据段以及任何附加数据段以覆盖分片键值的整个范围,并根据区域范围执行初始数据段分发。数据段的初始创建和分发可以更快地设置区域分片。
在初始分布之后,负载均衡器将管理未来的数据段分布。
- 对带有非哈希前缀的组合哈希分片键上的空集合进行分片
如果组合哈希分片键以哈希字段作为前缀(即哈希字段是分片键中的第一个字段):
没有为空集合或不存在的集合指定区域和区域范围:
分片操作会创建空数据段以覆盖分片键值的整个范围,并执行初始数据段分布。 所有非哈希字段的值在每个分割点均为
MinKey
。 默认情况下,该操作为每个分片创建 2 个数据块,并在集群中迁移。您可以使用numInitialChunks
选项指定不同数量的初始数据段。 数据段的初始创建和分布可以更快地设置分片。在初始分布之后,负载均衡器将管理未来的数据段分布。
为空collection或不存在的collection指定了范围从
MinKey
到MaxKey
的单个区域,并且将presplitHashedZones
选项指定为sh.shardCollection()
:该分片操作为定义的区域范围创建空数据段以及任何附加块以覆盖分片键值的整个范围,并根据区域范围执行初始数据段分布。数据段的初始创建和分布可以更快地设置区域分片。
在初始分布之后,负载均衡器将管理未来的数据段分布。
- 对带有非哈希前缀的组合哈希分片键上的空集合进行分片
如果组合哈希分片键有一个或多个非哈希字段作为前缀(即哈希字段不是分片键中的第一个字段):
如果没有为空的或不存在的collection指定区域和区域范围,并且preSplitHashedZones为
false
或省略,则 MongoDB 在对collection进行分片时不会执行任何初始数据块创建或分配。由于没有为空集合或不存在的集合 和 preSplitHashedZones 指定 区域和区域范围 ,
sh.shardCollection()
/shardCollection
会返回错误。对于空的或不存在的collection指定了区域和区域范围,并将preSplitHashedZones选项指定为
sh.shardCollection()
时:分片操作会为定义的区域范围创建空数据段和任何其他数据段,以覆盖分片键值的整个范围。
分片操作会进一步细分每个范围的初始数据段,以使该区域中的每个分片均分配到相同数量的数据段。
数据段的初始创建和分布可以更快地设置区域分片。在初始分布之后,负载均衡器将管理未来的数据段分布。
为每个区域定义的范围必须满足特定要求。有关要求说明和完整示例,请参阅为空集合或不存在的集合预定义区域和区域范围。
删除哈希分片键索引
从 MongoDB 5.0.22 开始, 您可以删除哈希分片键的索引。
这可以加快使用哈希分片键分片的集合的数据插入速度。在使用 mongosync
时,这还可以加快数据摄取速度。
有关详细信息,请参阅删除哈希分片键索引。