shard key必须有严格匹配的索引,否则mongos广播查询导致全分片collscan;索引字段顺序、方向须完全一致,不可稀疏或唯一(除非_id),哈希分片键需显式hashed索引。

shard key没索引会导致全分片扫描
mongos 没法靠裸字段值定位数据,必须依赖索引把 shard key 值映射到具体 chunk 和分片。没索引时,它只能向所有分片广播查询或写入——看起来像“扫描全表”,实际是每个分片都执行 COLLSCAN,explain() 里会看到大量 "stage": "COLLSCAN" 和 "stage": "SHARD_MERGE"。
shard key索引的硬性要求有哪些
不是随便建个索引就行,必须满足:
- 索引字段顺序必须严格匹配 shard key 的前缀(比如 shard key 是
{region: 1, userId: 1},那{region: 1}或{region: 1, userId: 1, status: 1}可用,但{userId: 1, region: 1}不行) - 方向必须一致(
{a: 1, b: -1}作 shard key,索引也得是{a: 1, b: -1};{a: 1, b: 1}不被接受) - 不能是稀疏索引(
sparse: true)、不能是唯一索引(除非是_id或明确用于强制 shard key 全局唯一) - 哈希分片键(
{field: "hashed"})允许建对应哈希索引,且从 MongoDB 6.0.12 起可删除
如何快速确认缺失索引
别凭感觉猜,三步直接验证:
- 连任意
mongos,运行sh.status(),确认目标集合已分片且显示了 shard key - 连到任一分片的主节点(不是 mongos),执行
db.getCollection('your_collection').getIndexes() - 检查输出中是否存在以 shard key 字段开头、类型为
1或-1的索引;常见漏掉的情况包括:只建了复合索引但顺序/方向不匹配,或误以为_id索引能替代
创建索引的时机和陷阱
空集合和非空集合处理方式完全不同:
- 集合为空时,
sh.shardCollection()会自动在 shard key 上建索引(如果尚不存在) - 集合已有数据,必须先手动建好索引,再调用
sh.shardCollection(),否则报错"cannot shard collection without an index on the shard key" -
sh.reshardCollection()会自动重建新 shard key 所需索引,无需提前干预 - 唯一索引一旦绑定 shard key,就不能删或 hide——除非是哈希分片键且 MongoDB ≥ 6.0.12
最常被忽略的是方向一致性:哪怕字段名和顺序都对,-1 和 1 差一个符号,索引就不可用。查 getIndexes() 输出时,务必盯住 key 字段里的数值符号。











