要定位document所属shard,需先计算其分片键值,再比对config.chunks中各chunk的[min, max)边界;迁移历史查config.changelog,document级无原生追踪,只能通过chunk边界与迁移日志推断。

Chunk 分布怎么看:直接查 sh.status() 不够用
想定位某个 Document 落在哪个 Shard,光看 sh.status() 只能知道集合的分片键范围和 Chunk 分布概览,没法反查具体 Document 归属。真正要追踪,得先算出它的分片键哈希值或范围位置,再比对 Chunk 的 min/max 边界。
实操建议:
- 用
sh.getSiblingDB("config").chunks.find({ ns: "db.collection" }).sort({ min: 1 })拉出所有 Chunk 元数据,重点关注min、max、shard字段 - 对目标 Document 的分片键值(比如
{ user_id: 12345 }),手动判断它落在哪个[min, max)区间——注意 MongoDB 的区间是左闭右开 - 如果分片键是复合键(如
{ a: 1, b: 1 }),必须按顺序拼接比较,不能只看单个字段;{ a: 1, b: 100 }可能比{ a: 2, b: 1 }小
迁移历史藏在哪:查 config.migrations 和 config.changelog
MongoDB 不记录单 Document 级别的移动日志,只记 Chunk 级迁移事件。真正能回溯“这个 Chunk 什么时候从 shard001 搬到 shard002”的,是 config.changelog 集合,而 config.migrations 只存当前进行中或失败未清理的迁移任务。
实操建议:
- 查迁移记录优先用
sh.getSiblingDB("config").changelog.find({ time: { $gt: ISODate("2024-01-01") } }).sort({ time: -1 }),过滤what: "moveChunk"类型 -
details字段里有from、to、min、max,可跟前面查到的 Chunk 边界对上号 - 注意
changelog默认只保留最近 24 小时(可通过mongos启动参数--chunklog或修改config.settings中的chunklog文档延长)
Document 级别无原生追踪:别指望 db.collection.findOne() 返回迁移痕迹
MongoDB 服务端不会给每个 Document 自动附加时间戳或来源 Shard 标识。所谓“流转路径”,本质是靠外部推断:先定位当前 Chunk → 查该 Chunk 历史迁移 → 推测 Document 曾经所在 Shard。没有内置字段、也没有钩子函数能实时捕获 Document 移动。
常见错误现象:
- 试图用
$where或聚合管道查 “Document 上次被读取的 Shard” —— 不存在这个元信息 - 在应用层写入时加
shard_hint或自定义字段模拟路径 —— 这只能记录写入点,无法反映后续 Chunk 迁移带来的物理位移 - 依赖
explain("executionStats")的executionStages.shards输出判断当前路由 Shard —— 它只反映查询发起时的路由结果,不是历史轨迹
性能与兼容性陷阱:查 config 库要权限,且高并发下 changelog 查询可能慢
直接读 config 数据库需要 clusterAdmin 或至少 clusterMonitor 角色,普通应用账号通常没权限。另外,changelog 在大集群中可能积累数万条记录,没建好索引时 find({ what: "moveChunk", time: { $gt: ... } }) 会全表扫。
实操建议:
- 提前在
config.changelog上建复合索引:db.changelog.createIndex({ what: 1, time: -1 }) - 避免在业务高峰期执行跨多个 Config Server 的
config查询;可考虑定期导出快照做离线分析 - 4.4+ 版本中,
sh.moveChunk()手动迁移会写入changelog,但自动均衡触发的迁移同样写入,两者字段结构一致,无需区分调用方式










