必须先为新分片键创建前缀索引,确保索引字段顺序一致且覆盖新片键;检查balancer启用、无movechunk、oplog窗口≥24小时;再执行reshardcollection命令完成四阶段迁移。

在MongoDB分片集群中,当业务写入模式变化导致现有分片键索引不再支撑均匀分布或高频查询时,必须通过重新分片(reshardCollection)来调整分片索引定义——这不是修改索引本身,而是重建整个分片结构并绑定新索引作为分片键依据,整个过程需满足原子性、索引前置和命令隔离等硬性条件。
确认新分片键已建好对应索引
执行 reshardCollection 前,【新分片键字段组合必须已在集合上建立支持索引】,且该索引必须以新分片键字段为前缀。例如新片键为 {region: 1, created_at: -1},则索引必须是 db.collection.createIndex({region: 1, created_at: -1}) 或更宽泛的 {region: 1, created_at: -1, status: 1},但不能是 {created_at: -1, region: 1}——顺序错即失败。
若原集合已有唯一索引(如 {user_id: 1} 唯一),而新片键不包含 user_id,则必须先确认新片键值全局唯一,否则 reshard 操作会在校验阶段中止。
这一步不可跳过,没有索引就发 reshard 命令会直接报错 “no matching index for shard key”。
停止干扰操作并检查集群状态
进入 mongosh,依次运行以下三组检查:
① 查看 balancer 是否启用:sh.getBalancerState() → 返回 true 才可继续;
② 确认无进行中的 moveChunk:sh.isBalancerRunning() → 必须返回 false;
③ 检查 oplog window:rs.printSecondaryReplicationInfo() → 最小窗口必须 ≥ 24 小时。
任意一项不满足,reshard 将被拒绝。特别注意:如果刚执行过 createIndex 或 drop,需等待至少 30 秒让命令缓存清空,否则 reshard 会因“命令冲突”失败。
执行重新分片命令
方法一:使用 adminCommand(推荐,返回字段完整)
db.adminCommand({
reshardCollection: "mydb.orders",
key: {region: 1, "meta.timestamp": -1},
unique: false,
numInitialChunks: 180
})
方法二:使用 sh.reshardCollection 辅助方法(语法简洁)
sh.reshardCollection("mydb.orders", {region: 1, "meta.timestamp": -1})
【必须指定完整命名空间,如 "mydb.orders",不能只写 "orders"】。若集合名含特殊字符或大小写混用,必须用双引号包裹字符串。
命令发出后,MongoDB 启动四阶段流程:克隆数据 → 构建新索引 → 追赶写入 → 提交切换。写入阻塞仅发生在最后提交阶段,约 2 秒。
验证迁移结果与清理
命令返回成功后,立即运行 sh.status(),重点核对两处:
• 分片键字段是否更新为新定义(Shard Key 行);
• 各分片 chunk 数是否开始重新均衡(Chunks 行数值差异应逐步缩小)。
若发现某分片 chunk 数长期远高于其他分片(如 >3 倍),说明新片键仍存在倾斜,需结合 db.orders.stats({scale: 1024*1024}) 查各分片数据量比值,比值 >1.5 即需二次审计。
旧分片键索引不会自动删除,如确认不再需要,手动执行 db.collection.dropIndex({old_key: 1})。











