大集合建索引易卡住或超时,需显式加{background:true}参数后台执行;分片集群须逐分片操作;unique索引须前台建并提前查重;需主动监控进度,故障后需手动重试。

大集合建索引会卡住或超时?先确认是否在后台运行
默认情况下,db.collection.createIndex() 是前台操作,会阻塞读写——对千万级以上文档的集合,这等于停服。必须显式加 { background: true } 参数,否则 mongosh 会长时间无响应,甚至触发连接超时。
- 前台建索引:锁整个集合,写入全部阻塞,适合低流量时段的小集合
- 后台建索引:
db.collection.createIndex({ field: 1 }, { background: true }),允许读写并发,但构建时间更长、CPU/IO压力更分散 - 注意:
background: true不适用于唯一索引(unique: true),后者必须前台执行以保证一致性
分片集群上建索引,别直接在 mongos 上跑命令
在分片集群里,对大集合建索引不能简单地在 mongos 上执行 createIndex()——它会向所有分片广播请求,但各分片可能进度不一,导致部分索引建完、部分失败,最终状态不可控。
- 正确做法:先用
sh.status()查清目标集合分布在哪些分片上 - 再逐个连接到对应分片的
mongod实例(不是 mongos),在每个分片上单独执行createIndex() - 若必须全局操作,且集合已启用分片键路由,可配合
setAllowMigrations: false暂停迁移,避免 chunk 迁移干扰索引构建
建索引前必须检查重复数据,尤其对 unique 索引
如果集合已有违反唯一约束的文档,createIndex({ field: 1 }, { unique: true }) 会直接失败并报错 duplicate key,且无法回滚已写入的索引碎片——你得手动清理数据再重试。
- 先用聚合查重:
db.collection.aggregate([ { $group: { _id: "$field", count: { $sum: 1 } } }, { $match: { count: { $gt: 1 } } } ]) - 对复合唯一索引,检查组合字段:
{ a: 1, b: 1 }要查{ $group: { _id: { a: "$a", b: "$b" }, count: { $sum: 1 } } } - 别依赖
dropDuplicates: true(已废弃),MongoDB 不提供自动去重建索引功能
监控索引构建进度,而不是干等
大集合建索引动辄几十分钟,光看命令没返回不等于卡死。要主动查状态,否则可能误判失败而中断操作,导致索引损坏或残留临时文件。
- 查当前活跃操作:
db.currentOp({ "command.createIndexes": { $exists: true } }) - 查索引列表及状态:
db.collection.getIndexes(),留意"building": true字段 - 在 admin 库查构建细节:
db.getSiblingDB("admin").aggregate([ { $currentOp: {} }, { $match: { "secs_running": { $gt: 60 } } } ])
真正容易被忽略的是:后台索引构建期间,如果节点发生故障或重启,索引会自动清理,但不会重试——你得自己重新发起命令,且无法续建,只能从头开始。











