db.collection.stats()在分片集群中仅返回单个分片(通常是primary shard)的局部统计,而非全局数据;应使用sh.getShardDistribution()跨分片聚合统计,或手动调用collStats命令兼容旧版本。

db.collection.stats() 在分片集群中只返回本地分片数据
直接在 mongos 上执行 db.collection.stats(),看到的 size、count 等字段仅反映当前 mongos 路由到的那个分片(或 primary shard)的局部统计,**不是整个集合的全局数据量**。这是最常被误用的点——你以为在查全量,其实只查了 1/N。
原因在于:mongos 不会自动聚合各分片的 stats 结果;它只是把命令透传给某个分片(通常是该集合的 primary shard),然后原样返回。
- 如果你的集合未分片(即还在 primary shard 上),
db.collection.stats()返回的是完整数据,但此时已不满足“分片集群统计”前提 - 如果集合已启用分片且有多个 chunk 分布,该命令对多数用户毫无参考价值
- 想确认是否真被分片,先跑
sh.status()或查sh.getShardDistribution()
用 sh.getShardDistribution() 快速看各分片文档数和空间占用
sh.getShardDistribution() 是 mongos 提供的专用工具函数,会主动向所有 shards 发起 collStats 并汇总,结果直观、开箱即用。
执行方式很简单,在 mongos shell 中:
use your_db_name
sh.getShardDistribution("your_collection_name")
输出包含每 shard 的 chunks 数、docs 文档总数、dataSize(字节)、storageSize 等关键指标,且自动按 shard 名排序。
- 注意:该函数要求 MongoDB ≥ 4.2;旧版本需手动聚合,见下一条
- 它底层调用的是
collStats命令(非stats),所以能跨分片收集 - 如果某 shard 暂时不可达,该函数会跳过并警告,不会中断整个统计
手动聚合 collStats:兼容老版本或需要自定义字段
当使用 MongoDB avgObjSize、nindexes)时,得自己发 collStats 到每个 shard。
步骤分三步:
- 先用
sh.status()或db.adminCommand({listShards: 1})获取 shard 列表 - 对每个 shard,通过
db.getSiblingDB("config").shards.find()解析连接地址(或直接从sh.status()复制) - 用
db.getMongo().getDB("admin").runCommand({collStats: "your_db.your_collection", scale: 1024})分别连各 shard 执行(注意:必须连 shard 的 mongod,不能连 mongos)
示例片段(在 mongos shell 中无法直接运行,需写脚本或逐个连接):
// 连 shard01:27018
mongo shard01:27018/admin --eval 'db.runCommand({collStats: "mydb.mycoll", scale: 1024})'
关键点:scale 参数控制单位(默认字节),设为 1024 得 KB,1024*1024 得 MB;不同 shard 的 storageSize 可能因压缩算法/存储引擎而差异显著。
为什么不要依赖 db.stats() 或 db.collection.countDocuments()?
db.stats() 返回的是整个数据库在当前 mongos 所连分片上的数据量,和 collection 级分片分布无关;countDocuments() 虽然能跨分片计数,但它走的是 query path,**不带 size 信息,且在大数据集上极慢、易超时**。
-
countDocuments()本质是执行一次全量分布式扫描,压力大、不准(可能含未提交事务影响) - 真正要评估磁盘占用,必须看
dataSize/storageSize,它们来自 storage engine 直接读取,快且准 - 若发现某 shard 的
docs明显偏少但storageSize很高,大概率存在大量删除后未 compact 的碎片,需关注collStats.wiredTiger.block-manager.fileSize(WiredTiger 引擎)
分片数据量失衡往往不是统计不准的问题,而是 chunk 迁移卡住、balancer 关闭、或片键选择不当导致的——统计只是第一步,后续得盯 sh.status() 的 chunk 分布和迁移日志。


















