深层嵌套字段索引必须使用完整点号路径(如"user.profile.age"),大小写和符号敏感;超10层嵌套或含数组会显著增加开销;复合索引需遵循esr原则,$expr禁用索引,低区分度字段即使ixscan也难提速。

深层嵌套字段必须用完整点号路径建索引
不能只写 "user.profile" 或 "age",MongoDB 不识别对象结构,只认字符串路径。比如文档是 {"user": {"profile": {"age": 25}}},要加速 user.profile.age 查询,索引键必须严格写成 "user.profile.age"。
大小写、空格、点号位置全敏感——"User.Profile.Age" 和 "user.profile.age" 是两个完全不同的索引键;字段值为 null、缺失或数组时,该索引项会被跳过,不影响查询结果,但可能降低命中率。
- 超 10 层嵌套(如
"a.b.c.d.e.f.g.h.i.j.k")索引构建和更新开销明显上升,需实测评估是否值得 - 路径中含数组(如
"user.hobbies.name")会触发多键索引行为,每个数组元素生成独立索引条目,易导致索引膨胀
复合索引里嵌套字段的顺序怎么排
按 ESR 原则:等值字段 → 排序字段 → 范围字段。但嵌套字段一旦出现在范围操作($gt、$regex、$ne)中,它之后的所有字段在该索引中就无法用于范围裁剪。
例如常查:{ "status": "active", "user.profile.score": { $gte: 80 }, "user.profile.tags": "vip" },索引应建为:{ "status": 1, "user.profile.score": 1, "user.profile.tags": 1 }。
-
$in算等值匹配,不影响后续字段的索引能力 - 如果
user.profile.tags是数组,且你用$elemMatch查内部对象,那user.profile.tags字段本身建索引就无效,得建在更深层路径上(如"user.profile.tags.name")
聚合管道里 $match 走不走深层索引
只在最前面的 $match 阶段走,且条件必须是“裸”谓词,不能包在 $expr 里。
这个能走索引:
[ {$match: {"user.profile.age": {$gte: 18}}}, {$addFields: {...}} ]
这个完全不走:
{ $match: {$expr: {$gte: ["$user.profile.age", 18]}} }——$expr 强制全表扫描计算。
- 后续阶段(如
$sort)若用到已索引字段,不会复用前面$match的索引,需要单独建含排序字段的索引 -
$lookup的本地字段如果是深层嵌套(如localField: "user.profile.id"),同样需要对应索引,否则关联性能极差
为什么 explain() 显示 IXSCAN 却还是慢
常见原因不是没建对索引,而是索引区分度太低:比如 user.profile.age 大量为 0 或 null,MongoDB 扫了 10 万条才凑够 100 条返回。
关键看 totalDocsExamined 和 nReturned 的比值。如果前者远大于后者(比如 50000 vs 25),说明索引虽被使用,但过滤效率差。
- 别只盯着
stage: "IXSCAN",更要关注totalKeysExamined和executionTimeMillisEstimate - 嵌套字段值重复高、分布倾斜时,即使建了索引也难提速,这时得结合业务逻辑改查询方式或预计算字段











