仅当唯一索引位于分片键上或包含分片键作为前缀时,分片集群才会跨分片实施唯一约束。本页介绍了如何在对集合分片分片时保持唯一性。
要在已分片的集合上创建唯一索引,请参阅在现有分片集合上创建唯一索引。要实施分片键键值的唯一性,请参阅强制分片键值的唯一性。要对不能作为分片键一部分的字段实施唯一性,请参阅对不是分片键的字段强制执行唯一性。
要对具有唯一性约束的集合重新分片,新的分片键必须满足任何现有唯一索引的唯一索引要求。有关详细信息,请参阅对集合重新分片。
关于此任务
唯一索引可确保索引字段不存储重复值。在分片的集合上,每个分片只能检查自己的数据是否存在重复项,因此,只有当保证具有给定索引键值的每个文档都位于同一分片上时, MongoDB才能在集群中实施约束。将分片键作为索引的前缀即可提供这种保证。
对于范围分片集合,只有以下索引是唯一的:
分片键上的索引
默认的
_id索引;但是,如果_id_id字段不是分片键,则 索引仅对每个分片强制执行唯一性约束。
唯一索引约束意味着:
对于要分片的集合,如果该集合有多个唯一索引,则无法对该集合分片,除非分片键是所有唯一索引的前缀。
对于已分片的集合,除非包含分片键作为前缀,否则无法在其他字段上创建唯一索引。
以下约束条件也应用:
不能在哈希索引上指定唯一约束。
分片键上的唯一索引会强制整个键组合的唯一性,而不是分片键的各个组件的唯一性。
重要
当 _id 字段不是分片键时,分片集群不会在整个集群中对 _id 字段执行唯一性约束。
如果 _id字段不是分片键,则唯一性约束仅应用于存储文档的分片。这意味着两个或多个文档可以具有相同的 _id 值,前提是它们出现在不同的分片上。
示例,考虑一个分片键为 {x: 1}的分片的集合,它跨越两个分片 A 和 B。由于 _id 键不是分片键,因此该集合可能在分片A 中包含 _id 值为 1 的文档以及分片B 中另一个 _id 值为 1 的文档。
如果 _id字段不是分片键, MongoDB希望应用程序确保各分片中 _id 值的唯一性,示例,使用唯一标识符填充 _id字段。
开始之前
确定集合的分片键。要查看分片的集合的分片键,运行
sh.status()方法并在输出中找到该集合。确认现有文档不违反该字段的唯一性约束。如果分片包含具有重复值的文档,则创建索引操作可能在没有重复项的分片上成功,但在有重复项的分片上失败,从而导致跨分片的索引不一致。
步骤
以下示例对 region_id 上的 accounts.names集合进行分片,并对 region_id 和 email 的组合实施唯一性约束。
对集合进行分片。
要对集合分片,运行sh.shardCollection() 方法:
sh.shardCollection( "accounts.names", { region_id: 1 } )
{ collectionsharded: 'accounts.names', ok: 1, '$clusterTime': { clusterTime: Timestamp( { t: 1759260515, i: 58 } ), signature: { hash: Binary.createFromBase64( 'AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0 ), keyId: Long( '0' ) } }, operationTime: Timestamp( { t: 1759260515, i: 57 } ) }
如果您对包含唯一索引的集合分片,而该索引不包含分片键作为前缀,则在您运行shardCollection 命令时, MongoDB会返回错误。