MongoDB故障码2620对应的错误信息通常是QueryExceededMemoryLimitNoDiskUseAllowed或者cursor id not found的变种场景,核心含义是服务端游标超时或排序聚合操作超出内存限制被强制终止。很多团队在遇到这个报错时第一反应是调大参数,但根因往往藏在索引层面:B树索引在长期高频率的写入和删除之后产生大量碎片,索引页稀疏、扫描效率下降,导致原本走索引的查询变成大范围扫描,内存占用飙升,最终触发2620故障码。所以处理这类问题,光改参数只是缓兵之计,做一次彻底的索引碎片整理才是治本方案。

故障码2620的触发机制与索引碎片的关系
先看故障本身。当查询引擎执行排序或聚合时,如果允许落盘的选项没有打开,而中间结果超过了100MB的内存上限,服务端会抛出错误。游标场景则类似:一个长时间扫描的游标在10分钟内没有返回数据,服务端会将其回收,客户端再取下一批数据时就报游标失效。这两类报错共享同一个错误码区间,排查时要先确认具体错误信息。
那索引碎片是怎么把查询拖垮的?MongoDB使用B树结构存储索引,删除文档时索引项不会立刻物理清除,只是标记为可复用。长期大量删除再插入的操作,会让索引页的填充率持续下降,一个原本紧凑的索引可能膨胀到初始体积的几倍。查询需要扫描的索引页数量随之增加,页缓存命中率下降,磁盘IO上升,扫描时间被拉长,超过游标超时阈值后故障码2620就出现了。可以通过下面的命令观察索引占用情况:
// 查看集合统计信息,关注 indexSizes 与 avgObjSize
db.collection.stats()
// 对比索引数量级与文档数量级是否合理
db.collection.countDocuments({})
// 查看具体某个索引的大小
db.collection.stats().indexSizes
如果发现某个索引的体积明显大于预期,比如单字段索引占用接近数据本身的大小,基本可以判定碎片化严重。另外观察cacheBytesReadIntoCache等WiredTiger缓存指标,若查询期间该指标陡增,也侧面印证了索引扫描效率的劣化。
判断碎片程度:哪些指标说明该整理了
并非所有情况都需要立刻动手。碎片整理本身有成本,尤其是对线上大集合,操作期间的IO压力不可忽视。判断是否需要整理,建议综合三个指标来看。
第一个是索引膨胀比。用db.collection.stats()拿到索引大小,与理论值做粗略对比。假设一个字段是8字节的整型,文档量一千万,理论上该索引应在几百MB量级,如果实际显示超过1GB,膨胀比就偏高了。第二个是查询延迟的长期趋势,通过db.setProfilingLevel(1, {slowms: 200})开启慢查询日志,观察同一类查询的执行时间是否随时间推移持续增长。第三个是执行计划中的扫描数量:
// 查看执行计划中的索引扫描键数量
db.collection.find({userId: 12345})
.sort({createTime: -1})
.limit(50)
.explain("executionStats")
重点看totalKeysExamined和nReturned的比值。健康状态下这个比值应该接近1,如果扫描了几万条键只返回几十条文档,说明索引选择性变差,碎片化或索引设计问题至少占一样。
三种碎片整理方案对比与实操
确定需要整理后,方案选择很关键。常用的有三种:compact命令、reIndex命令、滚动重建副本集成员。各有适用场景和风险,逐个说明。
第一种是compact。它对WiredTiger存储引擎的集合和索引做在线碎片回收,操作期间集合仍可读写,但会有一定的性能影响,官方建议在业务低峰期执行。对副本集环境,需要逐个节点执行,包括隐藏节点和延迟节点。命令如下:
// 对集合及其所有索引执行压缩,释放磁盘空间
db.runCommand({compact: "orders"})
// 仅压缩指定索引
db.runCommand({compact: "orders", index: "userId_1"})
compact的风险点在于执行时间不可控,大集合可能跑数小时,且主节点执行时可能触发流量波动。建议先在从节点验证效果,观察db.collection.stats()中索引大小的变化,再决定是否在主节点执行。
第二种是reIndex。它会删除并重建集合的所有索引,重建期间会持有独占锁,集合读写全部阻塞,所以只能用于允许停机的场景或从节点。优点是重建后的索引完全紧凑,效果最彻底:
// 重建集合的所有索引(会阻塞读写,慎用) db.orders.reIndex()
第三种是滚动重建,适合大规模生产集群。做法是逐台摘除副本集成员,清空数据目录后重新加入集群做全量同步,同步完成的节点会得到一份全新的紧凑数据。整个过程中集群始终保有足够的可用节点,对业务无感知。代价是全量同步消耗大量网络和IO带宽,且初始同步时间与数据量成正比,需要提前评估窗口期。
整理后的验证与预防措施
整理完成后不要急着收工,先做验证。重复之前的统计命令,对比索引大小,确认膨胀比回落到正常区间。再跑一遍explain("executionStats"),确认totalKeysExamined与返回数量的比值恢复正常。最后观察故障码2620是否还会复现,如果整理后依然报错,那问题可能不在碎片,而是查询本身缺少合适的复合索引,需要回到索引设计的层面重新审视。
预防方面,建议把碎片监控纳入日常巡检。定期采集各核心集合的索引大小,建立基线,膨胀比超过阈值比如两倍时就预警。对写入删除模式固定的业务,可以规划周期性的低峰compact。同时规范索引设计,避免冗余索引,因为每一个多余的索引都会放大碎片化的影响。另外在应用侧,排序聚合查询尽量显式设置allowDiskUse: true,给内存超限的情况留出落盘的退路,这样即使索引偶发劣化,也不至于直接抛出故障码2620。
总结一下处理思路:故障码2620是表象,索引碎片化导致的扫描效率劣化是常见根因。先用stats和explain确认碎片程度,再根据停机窗口和集群规模选择compact、reIndex或滚动重建,最后通过监控和索引规范防止问题复发。按这个流程走,绝大多数2620相关的性能问题都能得到根治。
MongoDB故障码2620索引碎片整理mongodb索引优化修改时间:2026-09-12 02:40:38