storageSize 与 size 差值反映磁盘碎片程度,差值越大成本越高;需通过 db.collection.stats() 检查 paddingFactor、avgObjSize 等字段评估,并在低峰期 compact 或重建集合。

直接看 storageSize 和 size 的差值
存储成本不是只看文档数量或集合大小,关键在磁盘实际占用与有效数据的比值。Robo 3T 的集合信息面板里,storageSize 是 MongoDB 分配的物理空间(含预分配和空洞),size 是当前 BSON 数据真实体积。两者差值越大,说明碎片越多、单位数据成本越高。
常见错误现象:日志类集合 storageSize 是 size 的 5 倍以上,但 count 没明显变化——这通常是频繁 delete/update 导致的空间无法自动回收。
- WiredTiger 引擎下,空洞不会自动释放,需手动执行
compact或重建集合 - 如果该集合长期只追加不删改,
storageSize ≈ size才是健康状态 - 注意:
compact是阻塞操作,生产环境建议在低峰期配合collMod调整storageEngine参数后再执行
用 db.collection.stats() 看真实碎片率
Robo 3T 图形界面只显示摘要,要精确评估得查原始统计。运行 db.collection.stats({scale: 1024})(单位 KB)重点关注这几个字段:
-
paddingFactor> 1.2:说明文档更新导致大量内部填充,写放大严重 -
avgObjSize接近 16MB 上限:嵌入过深或数组无节制增长,已逼近单文档硬限制 -
dataFileVersion为旧版本(如 0):可能还在用已弃用的 mmapv1 引擎,压缩和锁机制落后
性能影响:高 paddingFactor 会拖慢全表扫描;avgObjSize 过大会让 WiredTiger 缓存效率骤降——哪怕总数据量不大,也可能因单文档过大反复换页。
归档前先确认冷数据是否真“冷”
别光看时间戳字段判断冷热。MongoDB 没内置冷热标记,得结合访问日志 + 查询模式反推。例如一个 orders 集合,若最近 90 天的 find({status: "completed"}) 占全部查询 80%,而 find({createdAt: {$lt: ISODate("2025-01-01")}}) 几乎为零,才适合归档。
- 误判风险:按创建时间一刀切,但某些老订单可能因审计需求被高频查询
- 推荐做法:用
db.setProfilingLevel(2)开启慢查询日志,再用db.system.profile.find()统计历史查询中涉及的_id或时间范围 - 归档后必须保留索引策略:归档到低成本存储(如 S3 + Atlas Data Lake)时,原集合的
{createdAt: 1}索引失效,新查询需重设计
引用 vs 嵌入对存储成本的影响常被低估
表面看嵌入减少 JOIN,但冗余字段会直接推高 size。比如用户地址重复出现在 10 万条订单里,每条多存 200 字节,就是额外 20MB —— 这还没算索引膨胀。
- 引用方案的成本隐藏项:每个
addressId字段虽小(12 字节 ObjectId),但要额外维护addresses集合的索引和缓存 - 真正决定成本的是读写比例:读多写少 → 嵌入更省;写多读少 → 引用更省(避免重复更新)
- 特别注意:WiredTiger 的 zstd 压缩对重复字符串敏感,嵌入式地址字段在压缩后可能只占原体积 30%,但引用方案无法享受这种压缩增益
最易被忽略的一点:文档大小估算公式里的 ×1.2 安全系数,在高并发写入场景下会失真——BSON 编码器实际预留空间可能远超此值,尤其当字段名含 Unicode 或嵌套层级 >5 时。


















