分片之后,唯一索引还管用吗?_id 还是唯一的吗?怎样才能保证 email 全局唯一?这篇在两个分片上逐个情形验证。
create_index({email: 1}, unique) → code 67: cannot create index with 'unique' or 'prepareUnique' option over { email: 1 } with shard key pattern { uid: 1 } and collation {}", '$clusterTime': {'c分片集合上对非分片键建唯一索引,服务端直接拒绝(code 67),因为每个分片只能保证自己的那一份。
create_index({uid: 1, email: 1}, unique) → uid_1_email_1
{email: 1, uid: 1}(分片键不在前缀)→ code 67: cannot create index with 'unique' or 'prepareUnique' option over { email: 1, uid: 1 } with shard key pattern { uid: 1 } and collat唯一索引要以分片键为前缀({uid, email} 可以,{email, uid} 不行)。
同一个 uid、同一个 email → E11000 E11000 duplicate key error collection: test.u index: uid_1_email_1 dup 不同 uid(在另一个分片)、同一个 email → 成功 同一个分片内不同 uid、同一个 email → 成功 现在 email = a@x.com 的文档在各分片上的数量: [2, 1](全局并不唯一)
{uid, email} 的唯一索引只保证同一个 uid 下 email 不重复;不同 uid(在不同分片)可以有同样的 email。
第二个 _id = "same-id"(uid = 1600,落在另一个分片)→ 插入成功 _id = "same-id" 的文档在各分片上的数量: [1, 1];经 mongos 查 2 个 第三个 _id 相同、uid = 20(和第一个同一个分片)→ E11000
分片键不是 _id 时,_id 的唯一性只在单个分片内保证,不同分片上可以有相同的 _id。
同样的 email → E11000(全局唯一) a@x.com 与 z@x.com 分别在各分片上的数量: [1, 0] [0, 1]
让需要唯一的字段做分片键(或其前缀),并在 shardCollection 时指定 unique: true。
shardCollection(key={k: "hashed"}, unique=True) → code 72: Hashed shard keys cannot be declared unique. It's possible to ensure uniqueness on the hashed field by declaring an additional (non-hashed) unique index on the field., full error: {'ok': 0.0, 'errmsg': "Hashed shard keys cannot be
_id 用哈希做分片键:重复 _id → E11000(同一个 _id 哈希后总在同一个分片)哈希分片键不能声明 unique;但 _id 用哈希分片时,相同的 _id 必然落在同一个分片,实际上全局唯一。