MongoDB 慢查询分析
基于 MongoDB profiler 自动识别慢查询并给出索引优化建议,入口在「资源监控 → MongoDB」的慢查询页签。
前提
- 被诊断的 MongoDB 需在数据源页添加并启用,且用途勾选慢查询诊断。
- 多个启用诊断的实例(如分片集群的多个分片)会自动聚合分析,无需额外配置。
工作原理
- 开启 profiler:平台检测到目标库 profiling 未开启时,会自动执行
db.runCommand({profile:1, slowms:100})打开(这是平台对被监控库唯一的配置写入;不会创建索引、也不会写入业务数据)。若监控账号权限不足,日志中会出现Permission denied,此时需要手工开启,见下。 - 采集:每 10 分钟从 MongoDB
system.profile拉取一次,只看最近 120 分钟内的记录,单次最多取 2000 条。 - 筛选:只保留扫描文档数 ≥ 100000 的记录。注意「执行慢但扫描少」的查询不会被记录。
- 分组:按 query shape(忽略具体参数值的查询模板)聚合,同一指纹累计出现 ≥ 50 次才写入。每组显示累计次数、平均 / 最长耗时、扫描与返回文档数、典型样例。
- 存储:结果只写入平台自有的
ops-mongo,保留 7 天。 - 索引建议:结合查询字段组合与现有索引,给出可创建的复合索引,支持一键创建(后台调用
createIndex——这是唯一会往被监控库写入的操作,需要你主动点击)。
抓不到慢查询?先对照这四个条件
「慢」本身不是记录条件,真正的门槛是**「扫得多 + 跑得频繁」**,四个条件必须同时满足:
| 条件 | 默认值 | 可调环境变量 |
|---|---|---|
| 执行时长 | > 100 ms | ENV_GATEWAY_PROFILE_SLOW_MS |
| 扫描文档数 | ≥ 100000 | ENV_GATEWAY_DOCS_EXAMINED |
| 同指纹出现次数 | ≥ 50 次(最近 120 分钟内) | — |
| 采集周期 | 每 10 分钟一次 | ENV_GATEWAY_CAPTURE_INTERVAL_MS |
只造一条 20 秒的慢查询是抓不到的——它扫描量可能不足 10 万,出现次数也不够 50 次。要复现,典型做法是建一张 30 万行以上的大表,再用批量任务对它触发 50 次以上的全表扫描类查询。
刚触发完请等下一个采集周期再看;想更容易复现,可调小上表中的两个阈值。
排查:页面一直没有数据
按顺序检查:
- profiling 是否已开:在目标库执行
db.getProfilingStatus(),was应为1、slowms应为100。仍是0说明平台没能打开它,多半是监控账号权限不足。 system.profile里有没有货:为空说明造的数据没达到扫描量门槛,不是平台的问题。db.system.profile.find({ docsExamined: { $gte: 100000 } }).sort({ ts: -1 }).limit(5)- 上一步有货但页面仍为空:多半是同一指纹不足 50 次,或者还没到 10 分钟的采集周期。
手工启用 profiler(仅当账号权限不足时)
正常情况下平台会自动开启。若日志出现 Permission denied,在每个被监控库手工开启(slowms 为慢查询阈值,生产建议 100~500ms):
use mdwsrows; db.setProfilingLevel(1, { slowms: 100 })
use mdservicedata; db.setProfilingLevel(1, { slowms: 100 })
use mdworksheet; db.setProfilingLevel(1, { slowms: 100 })
use mdworkflow; db.setProfilingLevel(1, { slowms: 100 })
注意事项
- profiler 有约 1~3% 开销,生产只采
slowms阈值以上,不要用 level=2(全量采集)。 system.profile是 capped collection(默认 1MB),高 QPS 下滚动很快;需要更长留存可扩容:db.setProfilingLevel(0)db.system.profile.drop()db.createCollection("system.profile", { capped: true, size: 100000000 }) // 100MB- 一键建索引前评估对写入的影响,必要时低峰执行。