db.stats()无法识别未分片集合的磁盘占用,需逐个执行db.collection.stats()并检查shardKey字段是否为空,结合storageSize与size差异判断空间膨胀,再通过compact或重建优化。

查 db.stats() 不能直接看出未分片集合的磁盘占用
因为 db.stats() 返回的是整个数据库的汇总数据,不区分集合是否分片、是否启用分片键。真正占空间的大集合如果没开分片,会全量堆积在主分片(primary shard)上,但你从数据库级统计里完全看不出哪几个集合在“偷偷吃磁盘”。
实操建议:
- 必须逐个进入数据库,用
db.getCollectionNames()拿出所有集合名,再对每个集合调db.<collection_name>.stats()</collection_name> - 重点关注返回里的
size(原始 BSON 数据大小)、storageSize(实际磁盘占用,含 padding 和压缩开销)、shardKey字段是否存在 - 如果
shardKey是空对象{}或字段不存在,说明该集合**未启用分片** - 注意:
collStats命令在分片集群中需在mongos上执行,不能直连 shard 节点
用 sh.status() 看分片分布但无法反推空间占用
sh.status() 能告诉你哪些集合已分片、分片键是什么、chunk 分布在哪几个 shard 上,但它不提供每个 chunk 的大小,更不会告诉你某个未分片集合当前占了 20GB —— 它只说“这个集合没分片”,仅此而已。
实操建议:
- 先运行
sh.status()筛出所有shard key: {}的集合,记下名字和所属数据库 - 再切到对应数据库,对每个未分片集合单独执行
db.<collection_name>.stats({scale: 1024*1024})</collection_name>(单位转 MB,避免数字过大) - 特别留意
storageSize和nindexes:索引多、未压缩、大量删除后未 compact 的集合,storageSize会远大于size - 不要依赖
totalSize——它在 WiredTiger 引擎下已弃用,且不准确
写巡检脚本时绕不开 db.adminCommand("listDatabases") 和权限问题
想自动扫全集群所有库+所有集合,得先拿到数据库列表,而普通用户默认没有 listDatabases 权限;即使有,也未必对每个库都有 listCollections 权限。脚本一跑就卡在 not authorized,不是代码写错了,是账号没配对。
实操建议:
- 脚本开头必须用
db.adminCommand({listDatabases: 1, nameOnly: true})获取库名列表,不能硬编码或靠show dbs - 连接时用的角色至少要有:
clusterAdmin(用于sh.status()和listDatabases),加上每个目标库的read角色(否则db.<coll>.stats()</coll>会失败) - 在
mongos上执行,别在 shard 节点上跑——否则sh.status()报错,且stats()可能只返回本地 chunk 数据 - 加异常捕获:对每个集合执行
stats()时用try/catch,跳过权限不足或集合被删的 case,否则脚本中断
输出结果里 storageSize 高但 size 低?大概率要 compact 或重建索引
常见现象:一个未分片集合 storageSize 是 15GB,size 才 2GB。这说明磁盘上存了大量“空洞”——比如批量删除文档后没清理,或者旧版本 WiredTiger 表因频繁更新膨胀严重。
实操建议:
- 确认引擎是 WiredTiger(
db.serverStatus().storageEngine.name),只有它支持compact - 对未分片集合执行
db.runCommand({compact: "<collection_name>"})</collection_name>,但注意:该命令会阻塞写入,且只能在 主节点 上执行(不是 mongos) - 更稳妥的做法是:导出 + 删除 + 重建集合(
mongoexport→db.<coll>.drop()</coll>→mongoimport),顺便把索引也重做一遍 - 别忘了检查
db.<coll>.getIndexes()</coll>,冗余索引(如{a:1}和{a:1,b:1})也会持续占用storageSize
脚本跑出来最易被忽略的,是那些“刚建好还没写数据”的空集合——它们 shardKey 为空、storageSize 却有几 MB,其实是预分配的初始文件,不代表真实风险。真要判断空间压力,得盯住 storageSize > 100 <em> 1024 </em> 1024(100MB)且未分片的集合,其他先放一放。


















