queryShapeHash是MongoDB诊断慢查询的核心锚点,它标准化查询结构语义而非表象写法,支撑慢日志聚合、Profiler分析、explain验证及Atlas索引推荐,需结合多源数据闭环分析才能准确定位根因。

直接用 explain("executionStats") 看单次查询不够,真正要定位慢查询根因,得靠 queryShape ——它不是某个命令,而是 MongoDB 内部对查询“结构”的标准化哈希表示,是所有诊断工具(慢日志、profiler、explain)共用的锚点。
为什么 queryShapeHash 比看具体条件更可靠
同一个业务逻辑可能生成不同写法的查询(比如字段顺序调换、$eq 显式写出或省略),但只要语义等价,queryShapeHash 就一致。这意味着:
- 慢查询日志里按
queryShapeHash聚合,能真实反映“哪一类查询”拖慢了系统,而不是被表象写法干扰 -
system.profile中查出高metrics.queryExecutor.scanned的记录后,用queryShapeHash关联所有同类查询,才能判断是偶发还是普遍问题 - MongoDB Atlas 的 Performance Advisor 也是基于这个哈希推荐索引,不是靠猜字段
如何从慢日志/Profiler中提取并分析 queryShapeHash
先确保已启用慢日志或 profiler(推荐 db.setProfilingLevel(1, {slowms: 50}))。之后执行:
db.system.profile.find(
{ "millis": { "$gt": 50 } },
{ "queryShapeHash": 1, "query": 1, "millis": 1, "nReturned": 1, "docsExamined": 1 }
).sort({ "millis": -1 }).limit(5)
关键点:
- 别只盯着
"query"字段——它可能带随机值(如 ObjectId 或时间戳),掩盖真实模式 - 把输出里的
queryShapeHash值复制出来,在日志或 profile 集合中全文搜索,统计该哈希出现频次和平均耗时 - 如果某
queryShapeHash对应的docsExamined / nReturned比值远大于 1(比如 100:1),基本可断定缺索引或索引未命中
queryShape 在 explain 中怎么验证索引是否真生效
运行 explain("executionStats") 后,重点看两个地方:
-
queryPlanner.winningPlan.stage:如果是"IXSCAN",说明走了索引;如果是"COLLSCAN",就别信“有索引”这种说法 -
executionStats.executionStages.stage:这里显示实际执行路径,注意是否有"stage": "FETCH"——如果有,说明索引没覆盖查询字段,还得回表读文档 - 对比
executionStats.totalDocsExamined和executionStats.totalKeysExamined:前者远大于后者,就是索引选择不当或查询条件没用上索引前缀
queryShape 分析容易忽略的陷阱
很多团队把 queryShapeHash 当成“查询指纹”就完事,但实际使用中几个硬伤必须提前识别:
- 聚合管道中的
$lookup阶段,其子查询会生成独立的queryShapeHash,不会合并到主管道哈希里——得单独抓子查询的 profile 记录 - 开启可查询加密(QE)后,加密字段的等值查询会产生特殊 shape,且
explain中的indexName会显示为"__safeContent__",不能按普通索引理解 - 分片集群中,
queryShapeHash是在 mongos 层计算的,但各分片返回的 executionStats 里不带这个字段——你看到的哈希只代表路由层视角,不代表每个分片都执行了相同计划
真正有效的 queryShape 分析,从来不是截一个哈希去搜,而是把它当作串联慢日志、profile、explain 和 Atlas Advisor 的唯一 ID。漏掉任意一环,结论都可能偏移。



















