哈希分片
哈希分片使用单字段哈希索引或 复合哈希索引作为分片键,在分片集群中对数据进行分区。
- 对单字段哈希索引进行分片
哈希分片在分片集群中提供了更均匀的数据分布,但代价是减少了目标操作(相比广播操作)。经过哈希处理后,拥有“接近”分片键值的文档不太可能分布在同一数据段或分片上 -
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" } )
对填充的集合进行分片
如果使用哈希分片键对已填充的集合进行分片:
该分片操作会创建一个初始数据段以涵盖所有分片键值。
创建初始数据段后,负载均衡器会在需要均衡数据时移动初始数据段的范围。
对空集合进行分片
分片集合操作可以对空集合或不存在的集合执行初始数据块创建和分发,前提是已为该集合定义区域和区域范围。数据段的初始创建和分布可以更快地设置区域分片。在初始分布之后,负载均衡器将照例管理未来的数据块分布。
- 使用单字段哈希分片键对空集合进行分片
没有为空集合或不存在的集合指定区域和区域范围:
分片操作会创建一个空数据块来覆盖分片键值的整个范围。从版本 7.2 开始,该操作默认为每个分片创建 1 个数据段,并在集群中迁移。 您可以使用
numInitialChunks
选项指定不同数量的初始数据块,并进行初始数据块分布。数据块的初始创建和分布可以更快地设置分片。在初始分布之后,负载均衡器将管理未来的数据段分布。
为空集合或不存在的集合指定了区域和区域范围:
分片操作为定义的区域范围创建空数据段以及任何附加数据段以覆盖分片键值的整个范围,并根据区域范围执行初始数据段分发。数据段的初始创建和分发可以更快地设置区域分片。
在初始分布之后,负载均衡器将管理未来的数据段分布。
- 对带有非哈希前缀的组合哈希分片键上的空集合进行分片
如果复合哈希分片键将哈希字段作为前缀(哈希字段是分片键中的第一个字段):
没有为空集合或不存在的集合指定区域和区域范围:
分片操作会创建空数据块以覆盖分片键值的整个范围,并执行初始数据块分布。所有非哈希字段的值在每个分割点均为
MinKey
。 从版本 7.2 开始,该操作默认为每个分片创建 1 个数据段,并在集群中迁移。 您可以使用numInitialChunks
选项指定不同数量的初始数据块,并进行初始数据块分布。This initial creation and distribution of chunks allows for faster setup of sharding.在初始分布之后,负载均衡器将管理未来的数据段分布。
如果为空的或不存在的集合指定了范围从
MinKey
到MaxKey
的单个区域并且presplitHashedZones
选项指定为sh.shardCollection()
:该分片操作为定义的区域范围创建空数据段以及任何附加块以覆盖分片键值的整个范围,并根据区域范围执行初始数据段分布。数据段的初始创建和分布可以更快地设置区域分片。
在初始分布之后,负载均衡器将管理未来的数据段分布。
- 对带有非哈希前缀的组合哈希分片键上的空集合进行分片
如果组合哈希分片键有一个或多个非哈希字段作为前缀(即哈希字段不是分片键中的第一个字段):
如果没有为空集合或不存在的集合指定区域和区域范围,并且 preSplitHashedZones 为
false
或省略,则 MongoDB 在对集合进行分片时不会执行任何初始数据块创建或分布。如果没有为空集合或不存在的集合指定区域和区域范围,并且 presplithashedZones,则
sh.shardCollection()
/shardCollection
会返回错误。如果为空集合或不存在的集合指定了区域和区域范围,并且 presplitHashedZones 选项指定为
sh.shardCollection()
:分片操作会为定义的区域范围创建空数据段和任何其他数据段,以覆盖分片键值的整个范围。
分片操作会进一步细分每个范围的初始数据段,以使该区域中的每个分片均分配到相同数量的数据段。
数据段的初始创建和分布可以更快地设置区域分片。在初始分布之后,负载均衡器将管理未来的数据段分布。
为每个区域定义的范围必须满足特定要求。有关要求说明和完整示例,请参阅为空集合或不存在的集合预定义区域和区域范围。
删除哈希分片键索引
从 MongoDB 7.0.3(以及 6.0.12 和 5.0.22)开始,您可以删除哈希分片键的索引。
这可以加快使用哈希分片键分片的集合的数据插入速度。在使用 mongosync
时,这还可以加快数据摄取速度。
有关详细信息,请参阅删除哈希分片键索引。