上一篇讲了片键设计的三个目标,这一篇讲片键选好后,怎么分——范围分片还是哈希分片。这是同一个片键的两种分散策略,它们直接决定了:范围查询能不能定向、写入会不会热点。选错了,要么查询全广播,要么写入堆在一个 shard。
先把机制边界说清楚
MongoDB 把数据按片键划分成 chunk,划分方式有两种:
- 范围分片(Ranged Sharding):按片键值的大小范围划分。比如片键是数值,
[1,1000)一个 chunk、[1000,2000)一个 chunk。相邻的值在同一个 chunk(大概率同一 shard)。 - 哈希分片(Hashed Sharding):按片键值的哈希划分。先算片键值的哈希,按哈希值范围划分。相邻的原始值,哈希后分散到不同 chunk。
两者的本质差别是:范围分片保留了片键的顺序性,哈希分片打散了顺序性。这个差别决定了它们各自擅长什么。
范围分片 vs 哈希分片
范围分片的优势是范围查询能定向。因为相邻的片键值在同一个 chunk/同 shard,查询 {createdAt: {$gte: X, $lt: Y}} 这种范围条件,mongos 能算出涉及哪些 chunk,定向到对应 shard,不用广播。这对时间范围、数值区间的查询非常友好。
范围分片的劣势是单调递增会热点。如果片键单调递增(时间戳、自增 ID),所有新数据的片键值都比现有的大,全落进「最大值」那个 chunk,而这个 chunk 通常在最后一个 shard。于是所有写入集中到一个 shard,形成严重热点——这个 shard 扛着全部写入,其他 shard 闲置,完全失去了分片的负载分散意义。
哈希分片的优势是写均匀分散。哈希把单调递增的值打散成随机分布,写入均匀打到各个 shard,没有热点。这对写入量大的场景(日志、事件流、IoT)非常关键。
哈希分片的劣势是范围查询无法定向。哈希后片键值失去了顺序性,原本相邻的值分散到不同 chunk。范围查询不知道涉及哪些 chunk,只能广播到所有 shard。所以哈希分片不适合有范围查询需求的场景。
怎么选
选择的核心是两个问题:业务有没有范围查询?片键会不会单调递增?
有范围查询需求(时间、数值区间)→ 范围分片。但要确保片键不是单调递增的,否则热点。如果片键本身就是递增的(比如时间),范围分片会热点,这时要么换片键,要么用下面的混合策略。
无范围查询、按 ID 等值查询 → 哈希分片。写入均匀是最大优势,ID 等值查询能定向(按哈希值定位 chunk)。日志、事件、按文档 ID 查的场景适合。
两者都要(既有范围查询又怕热点)→ 混合策略。几种做法:
- 复合片键 {范围字段, 哈希字段}:比如
{userId, 时间}范围分片,userId 分散写入、时间聚合同用户数据。或者对单调键加一个分散前缀。 - 对单调递增键做哈希分片 + 辅助索引:片键用哈希保证写均匀,范围查询靠在非片键字段建索引(虽然查询会广播,但索引在各 shard 内高效)。
- 权衡接受广播:如果范围查询不频繁,哈希分片 + 偶尔广播也能接受。
几个实际场景的推荐
日志/事件流(写入大、按 ID 查、偶尔按时间扫):哈希分片(按文档 ID 或机器 ID 哈希),写均匀是第一优先。
用户内容/订单(按用户维度访问):范围分片 {userId, 时间},用户查询定向、单用户数据聚集、写入按用户分散。
时间序列数据(按时间范围查、写入单调递增):最棘手的场景。纯时间范围分片会热点。可用 {标签字段, 时间} 复合片键(标签字段分散写入,时间保范围查询),或桶模式 + 哈希。
纯 ID 查询(KV 场景):哈希分片,简单高效。
判断框架
- 范围分片保范围查询、牺牲写分散;哈希分片保写均匀、牺牲范围查询。
- 高频范围查询 → 范围分片,但警惕单调递增热点。
- 写入大、ID 等值查询 → 哈希分片。
- 两者都要 → 复合片键或哈希+辅助索引。
- 时间序列是最难的场景,用复合片键或桶模式。
- 记住:范围查询多别用哈希;写入怕热点别用范围分单调键。
下一篇讲 chunk 和 balancer,看清数据怎么在 shard 间均衡。
关于十三Tech
我是十三,All in AI Agent 方向的架构师,专注 AI 工程实践。
我相信 AI 是程序员的最佳搭档,也希望帮助每一位开发者更好地驾驭 AI。
如果你想继续跟完这套「图解 MongoDB」,欢迎关注公众号 「十三Tech」。后续会按分片集群和架构选型这条线更新。

