必须执行compact命令才能真实回收索引空间,因wiredtiger仅标记索引页为“可复用”而不归还os;需在primary上运行db.runcommand({compact: "mycol", force: true}),并提前检查磁盘余量、孤儿chunk及停写。

在MongoDB 4.4中执行大量deleteMany()或remove()后,索引文件大小几乎不变,磁盘空间不释放,是因为WiredTiger仅标记索引页为“可复用”,并不主动归还给操作系统——此时必须通过compact命令物理重写索引文件才能真实回收空间。
确认是否真需compact
先验证当前集合是否存在索引碎片:运行db.mycol.stats(),重点对比indexSize与storageSize。若indexSize远大于实际文档索引开销(例如10万条文档却占2GB索引),且删除操作已持续数小时未见磁盘下降(df -h无变化),说明碎片已堆积,compact必要。
注意:【compact不能在secondary节点执行,只对primary生效】。运行rs.isMaster().ismaster确认返回true,否则命令静默失败。
执行前三大必查项
① 检查磁盘余量:compact期间会生成新.wt文件,临时占用≈原集合totalSize的1.2倍。执行df -h /data/mongodb,确保目标路径剩余空间≥(collection size + index size) × 1.2,否则compact中途因磁盘满而中止,留下损坏状态。
② 扫描孤儿chunk:若集合属GridFS(fs.files/fs.chunks),仅删fs.files文档而未清理对应fs.chunks,compact完全不可见这些块,空间照占。运行db.fs.chunks.find({files_id: {$not: {$in: db.fs.files.distinct("_id")}}}).count(),结果非零必须先清理。
③ 停写或切维护窗口:compact期间若发生写入,可能触发WiredTiger内部冲突导致命令失败。生产环境务必暂停应用写入,或安排在低峰期执行。
强制重建索引的真实操作步骤
别用db.runCommand({compact: "mycol"})——它默认不保证索引文件重写,实测在4.4中索引空间回收率常低于15%。
必须显式启用force参数:db.runCommand({compact: "mycol", force: true})。force:true强制WiredTiger丢弃所有旧索引页并重建完整B-tree结构,这是4.4+版本中索引空间下降20%–60%的关键开关。
执行后立即验证效果:再次运行db.mycol.stats().indexSize,数值应明显低于compact前;再登录服务器执行ls -lh /data/mongodb/*/mydb/mycol-*.wt,索引文件(含idx开头的.wt文件)体积须同步收缩。
若该集合含TTL索引,compact后补一句db.mycol.reIndex(),防止TTL后台线程残留的元数据干扰后续过期扫描。











