分片键决定两件事
分片键同时决定数据分布与查询路由:基数要高、取值频率要均匀、避免单调递增。它一旦选定就很难更改,所以要在上线前按真实查询清单验证,而不是等数据量上来再调整。
范围键与散列键的取舍
范围分片键保留区间有序性,便于范围查询与就近路由,但单调递增的键会把写入集中到最后一个分片;散列分片键能把写入打散,代价是范围查询需要扇出到所有分片核对。按时间检索多、又要求写入分散时,可以评估复合分片键。
基本信息
| 高基数 | 候选值足够多,避免少数分片承载大部分数据 |
|---|---|
| 低频率 | 单个取值不集中,热点取值不适合做分片键 |
| 非单调 | 写入不落在同一区间,散列键可缓解单调键的写入集中 |
| 改写成本 | 分片键需要重建集合或迁移数据才能调整 |
| 适用范围 | 以分片集群为例,思路对同类系统通用 |
启用分片与选择分片键
启用分片与选择分片键
sh.enableSharding("app")
// 散列分片键:写入分散,范围查询需要扇出
sh.shardCollection("app.events", { deviceId: "hashed" })
sh.status()
// 复合分片键:先按租户散列,再按时间排序
sh.shardCollection("app.events", { tenantId: "hashed", ts: 1 })
// 查看各分片的数据分布,确认是否均衡
db.events.getShardDistribution()典型使用场景
- 新集合分片:按访问模式选择范围键或散列键
- 热点治理:写入集中的集合改用散列键或复合键
- 多租户隔离:用租户标识作为分片键前缀,减少跨分片查询
- 容量规划:结合分片键分布估算各分片的增长
- 上线验证:按查询清单确认常用查询能命中分片键
分片键形态与代价
| 分片键形态 | 优势 | 代价 |
|---|---|---|
| 范围键(如时间) | 范围查询与就近路由高效 | 单调递增会把写入压到单个分片 |
| 散列键 | 写入分布均匀 | 范围查询需要扇出到所有分片 |
| 复合键 | 兼顾分布与局部有序 | 设计复杂度上升 |
| 低基数键 | 实现简单 | 分片间无法均衡,容易形成热点 |
分片键影响路由与均衡:范围查询在散列键上需要访问所有分片;按时间检索多又要求按租户隔离时,复合分片键往往更合适。
用自增 ID 或时间戳作为唯一分片键会把写入集中到单个分片形成热点;分片键选择后修改成本很高,通常要重建集合并迁移数据。