MongoDB Profiling可通过db.setProfilingLevel(1, {slowms: 100})开启慢聚合记录,它原生捕获超阈值的aggregate命令;查询system.profile中command.aggregate存在且millis > 100的文档即可定位慢聚合管道,并结合nscannedObjects、keysExamined等字段分析索引使用与阶段瓶颈。

如何开启 MongoDB Profiling 记录慢聚合查询
MongoDB 的 profiling 是最直接、无需额外工具就能捕获慢聚合管道的方法。它不依赖应用层埋点或 APM,只要数据库有权限,就能在服务端原生记录执行时间超阈值的命令,包括所有 aggregate 调用。
启用方式很简单,但关键参数容易设错:
-
db.setProfilingLevel(1, { slowms: 100 }):只记录耗时 ≥100ms 的操作(推荐从 100 开始,避免日志爆炸) -
db.setProfilingLevel(2):记录全部操作(仅调试用,生产环境禁用) -
db.setProfilingLevel(0):关闭(默认状态)
注意:slowms 是毫秒级阈值,对聚合尤其敏感——一个未命中索引的 $match 阶段就可能轻松突破 500ms;而带 $lookup 或多阶段 $group 的管道,在数据量稍大时很容易卡在秒级。
从 system.profile 中查出慢聚合的具体 pipeline
Profiling 日志写入 system.profile 集合,每条文档包含完整命令、执行时间、扫描文档数等关键字段。
执行以下查询可快速定位最近的慢聚合:
db.system.profile.find({
"command.aggregate": { $exists: true },
"millis": { $gt: 100 }
}).sort({ "ts": -1 }).limit(5)
返回结果中重点关注这几个字段:
-
command.aggregate:原始聚合管道数组(含所有阶段,如$match、$group) -
millis:总耗时(单位 ms) -
nreturned:最终返回文档数 -
nscannedObjects:实际读取的文档数(若远大于nreturned,说明过滤太晚或没索引) -
keysExamined:索引扫描次数(若为 0,基本确认没走索引)
⚠️ 常见陷阱:误以为 explain("executionStats") 输出里的 executionTimeMillis 和 profiling 的 millis 总是一致——其实 profiling 记录的是整个命令生命周期(含网络、锁等待),更贴近真实延迟。
为什么 profiling 比 explain() 更适合线上问题初筛
explain() 必须手动加到聚合语句前,你得先知道哪条聚合慢;而 profiling 是被动监听,只要慢了就会留痕,适合排查“谁在拖垮系统”的未知问题。
但它也有局限:
- 不记录客户端 IP 或应用名(除非你用
client字段自定义打标) - 无法关联上下游调用链(比如哪个 HTTP 接口触发了该聚合)
-
system.profile默认是 capped collection,容量有限(通常 1MB),老日志会被自动覆盖
所以线上建议组合使用:用 profiling 快速捞出可疑 pipeline → 复制到 Robo 3T 或 shell 中加 .explain("executionStats") 深挖瓶颈阶段 → 再结合 db.collection.getIndexes() 验证索引是否生效。
聚合管道里哪些 stage 最容易触发 slowms 告警
不是所有阶段都“平等”消耗时间。以下 stage 在 profiling 日志中反复出现高 millis,往往指向明确优化方向:
-
$lookup:若nscannedObjects极高,说明被关联集合缺少 on 字段索引 -
$unwind:数组过大时会指数级膨胀文档数,nscannedObjects可能比原始集合还大十倍 -
$group+$sum/$avg:内存占用飙升,若 profiling 中看到"errmsg": "Sort exceeded memory limit...",说明必须加allowDiskUse: true -
$text或 Atlas Search 相关 stage:全文检索本身开销大,配合$match顺序错误会雪上加霜(比如先$group再$match)
真正难缠的,是那些看起来“只是加了个 $project”却让 millis 翻倍的管道——这时候大概率是投影字段引用了未索引的嵌套路径,或触发了隐式类型转换(比如字符串字段用 $gt: 100 查询)。











