profiler 里一条查询 millis 是 1200,nreturned 只有 10,docsExamined 却有 200000,等于翻了整张集合。日志里能对上时间点,这种反而好排。
过滤字段上没有可用索引,只能整集合顺序扫,翻完才返回那十条,扫描量和返回量差了几个数量级,补索引前先确认这一点。这一点先确认清楚,后面就不用反复试。
db.setProfilingLevel(1, { slowms: 100 });
db.system.profile.find({ millis: { $gt: 500 } })
.sort({ ts: -1 }).limit(5);
db.orders.createIndex({ status: 1, created_at: -1 });
围绕「MongoDB 慢查询分析」排查时,命令行跑一遍比在面板里点十次有用,面板会替你做掉不少隐式操作。先做最小复现,能稳定跑出来的问题,排查成本会低一个数量级。
别只看报错的最后一行,往上看几行,真正的起因通常在上面。同类问题如果隔一段时间又出现,多半是某个定时任务或重启流程把改动冲掉了。
处理上按这个顺序:打开 profiler 按耗时把最慢的几条捞出来;按过滤字段等值在前、范围在后的顺序补索引;对比扫描键数和扫描文档数的比值,判断索引有没有白建。
结果对不对很好判断,扫描文档数降到与返回条数同一量级,耗时落到 30ms 内。
