分片键
分片键可以是单个索引字段字段或者由一个组合索引覆盖的多个字段,该索引决定了集合的文档在集群的分片间的分布。
MongoDB将分片键值的范围(或哈希分片键值)划分为不重叠的分片键值范围(或哈希分片键值)。每个范围都关联一个数据块,MongoDB试图在集群中的分片间均匀分配数据块。
分片键与数据块分配的有效性有直接关系。请参阅选择分片键。
分片键索引
所有分片集合必须有一个支持分片键的索引。该索引可以是分片键的索引,或者分片键是索引前缀的组合索引。
如果集合为空,则当不存在这样的索引时,
sh.shardCollection()
将在分片键上创建索引。如果集合不为空,则在使用
sh.shardCollection()
.之前必须先创建索引。
如果该索引是唯一支持分片键的非隐藏索引,则不能删除或隐藏索引。
唯一索引
MongoDB可以对分片键索引强制唯一性约束。通过在分片键上使用唯一索引,MongoDB强制整个键组合的唯一性,而不仅仅是分片键的各个组件。
对于范围分片集合,以下索引可以是唯一索引:
重要
只有当_id
字段也是分片键时,分片集群才在集群中强制执行_id
字段的唯一性约束。
如果_id
字段不是分片键或只是分片键的前缀,唯一性约束只适用于存储文档的分片。这意味着两个或多个文档可以具有相同的_id
值,前提是它们出现在不同的分片上。
例如,考虑一个具有分片键{x: 1}
跨越两个分片A和B的分片集合。因为_id
键不是分片键,所以该集合可以在分片A中有一个_id
值为1
的文档,并在分片B中另一个具有相同_id
值的文档。
当_id
字段不是分片键时,MongoDB期望应用程序在分片之间强制执行_id
值的唯一性。
唯一索引约束意味着
对于一个即将分片的集合,如果集合有多个唯一索引,则不能对该集合进行分片,除非分片键是所有唯一索引的前缀。
对于一个已经分片的集合,除非将分片键包含为前缀,否则不能在其他字段上创建唯一索引。
唯一索引为缺失索引字段的文档存储一个null值;也就是说,缺失的索引字段被视为另一个实例的
null
索引键值。有关更多信息,请参阅唯一单字段索引中的缺失文档字段。
为了强制分片键值唯一性,将 unique
参数设置为 true
传递给 sh.shardCollection()
方法
如果集合为空,
sh.shardCollection()
将在分片键上创建唯一索引(如果尚不存在)。如果集合不为空,则在使用
sh.shardCollection()
.之前必须先创建索引。
尽管您可以有唯一 复合索引,其中分片键是 前缀,但如果使用 unique
参数,集合必须有一个唯一索引,且该索引位于分片键上。
您不能在 哈希索引 上指定唯一约束。
要在非分片键的字段上维护唯一性,请参阅 任意字段的唯一约束。
缺少分片键字段
分片集合中的文档可能缺少分片键字段。要设置缺少的分片键字段,请参阅 设置缺少的分片键字段。
数据块范围和缺少分片键字段
缺少的分片键字段位于具有 null 值的分片键相同的块范围内。例如,如果分片键在字段 { x: 1, y: 1 }
上,那么
文档缺失分片键 | 属于与以下相同的范围 |
---|---|
{ x: "hello" } | { x: "hello", y: null } |
{ y: "goodbye" } | { x: null, y: "goodbye" } |
{ z: "oops" } | { x: null, y: null } |
读/写操作和缺失分片键字段
为了定位缺失分片键字段的文档,您可以在分片键字段上使用 { $exists: false }
过滤条件。例如,如果分片键位于字段 { x: 1, y: 1 }
上,您可以通过运行此查询来找到缺失分片键字段的文档
db.shardedcollection.find( { $or: [ { x: { $exists: false } }, { y: { $exists: false } } ] } )
如果您指定了一个 空值匹配 过滤条件(例如 { x: null }
),则过滤器将匹配这两个 缺失分片键字段的文档 以及 将分片键字段设置为 null
的文档。
某些写操作,例如带有 upsert
规范的写操作,需要在分片键上匹配相等。在这些情况下,为了定位缺失分片键的文档,除了空值匹配之外,还需要包含另一个过滤器条件。例如
{ _id: <value>, <shardkeyfield>: null } // _id of the document missing shard key