MongoDB索引损坏时需按四步修复:先用db.collection.validate({full: true})确认损坏;再停写并清理长事务;然后后台重建索引(注意字段顺序)或reIndex()全量重建;最后验证validate结果、查询执行计划及索引数量。

当MongoDB因断电、强制kill或进程崩溃导致索引结构损坏时,常见现象是查询返回空结果、countDocuments()值异常偏低、$sort阶段卡死或报KeyNotFound错误——此时不能直接删库重来,必须在保障服务可用的前提下完成修复。
第一步:确认是否真为索引损坏
连接到mongosh,切换目标数据库后执行:db.collection.validate({full: true})。
重点看返回中的valid字段和errors数组;若valid: false且errors包含Index key mismatch或Invalid index entry,即可锁定为索引层逻辑损坏,不是文档存储物理损坏。
【不要跳过 full: true 参数】省略该参数时validate仅做轻量校验,可能漏掉深层索引指针断裂问题,导致误判为“正常”而跳过修复。
第二步:停写并清空长事务
索引重建(尤其是前台)会获取集合级排他锁,若此时有活跃写入,极易触发超时中断,留下半成品索引——后续validate仍报错,且无法再次drop。
运行db.currentOp({secs_running: {$gt: 10}})查看运行超10秒的操作。
对非关键写操作执行db.killOp(opId),优先清理updateMany、findAndModify类长事务。
确认无写入后,用db.collection.stats().wiredTiger.cursor.list检查是否仍有未释放游标——若有,需等其自然超时或重启连接。
第三步:安全重建索引
方法一:后台重建(推荐)
执行db.collection.dropIndex("index_name")删除损坏索引;若报错Index not found或卡住,改用db.runCommand({dropIndexes: "collection", index: "index_name"})绕过元数据校验。
重建时务必加{background: true}选项:db.collection.createIndex({a: 1, b: -1}, {background: true})。即使集合只有几万条,也别省略——后台模式只持读锁,不影响线上查询。
方法二:复合索引字段顺序必须严格一致
原索引是{status: 1, createdAt: -1, userId: 1},重建时字段名、方向、顺序三者缺一不可;调换createdAt和userId位置会导致查询计划器完全忽略该索引,看似重建成功,实则无效。
方法三:跳过单个索引重建,用全量重建兜底
若不确定哪个索引损坏,或多个索引同时异常,可执行db.collection.reIndex()。它会逐个重建所有索引,但会短暂阻塞写入——仅限低峰期使用,且必须确保已停写。
第四步:验证修复结果
① 运行db.collection.validate({full: true}),确认valid: true且errors为空数组。
② 执行典型业务查询,例如db.collection.find({status: "paid"}).sort({createdAt: -1}).limit(10).explain("executionStats"),检查executionStats.nReturned是否符合预期,executionStats.executionStages.stage是否为IXSCAN而非COLLSCAN。
③ 对比修复前后索引数量:db.collection.getIndexes().length应与修复前一致;若减少,说明某索引重建失败但未报错,需重新执行对应createIndex命令。

















