← 返回题目列表

MongoDB 索引怎么设计?复合索引和最左前缀怎么理解?

高频 中等 第 13 / 31 题 更新于 2026/07/28
MongoDB索引复合索引查询优化

简化版

MongoDB 索引用来加速查询和排序,常见有单字段索引、复合索引、多键索引、文本索引、TTL 索引等。复合索引要按照高频查询条件设计,通常遵循 ESR 思路:Equality 等值字段在前,Sort 排序字段其次,Range 范围字段靠后。索引能提升读性能,但会增加写入、更新和存储成本。

详细版

常见索引:

  • 单字段索引:{ userId: 1 }
  • 复合索引:{ userId: 1, createdAt: -1 }
  • 多键索引:数组字段上的索引;
  • 唯一索引:保证字段唯一;
  • 文本索引:文本搜索;
  • TTL 索引:自动过期删除;
  • 部分索引:只索引满足条件的文档。

示例:

db.orders.createIndex({ userId: 1, createdAt: -1 })

它适合:

db.orders.find({ userId: 100 }).sort({ createdAt: -1 })

不要给所有字段都建索引。索引越多,写入越慢,占用空间越多,优化器选择也更复杂。

完整版教学

一、索引解决的是扫描范围问题

没有索引时,MongoDB 可能需要扫描大量文档才能找到结果。索引像目录,可以按字段值快速定位候选文档。

例如订单集合有 1 亿条,如果按用户查订单:

db.orders.find({ userId: 100 })

没有 userId 索引,就可能扫描大量数据;有索引后,可以快速定位该用户订单。

二、复合索引要服务具体查询

复合索引:

db.orders.createIndex({ userId: 1, status: 1, createdAt: -1 })

适合:

db.orders.find({
  userId: 100,
  status: "PAID"
}).sort({ createdAt: -1 })

字段顺序不是随便排的。要看等值过滤、排序和范围条件的组合。

三、最左前缀怎么理解

复合索引 { a: 1, b: 1, c: 1 } 通常可以支持:

  • { a: 1 }
  • { a: 1, b: 1 }
  • { a: 1, b: 1, c: 1 }

但如果查询只有 { b: 1 },就不能很好利用这个复合索引的前缀。

所以复合索引设计前,要先统计高频查询形态,而不是看字段重要程度拍脑袋。

四、ESR 是常见设计思路

MongoDB 官方文档推荐过 ESR 这类思路:等值字段、排序字段、范围字段按查询特点安排。

例如:

db.logs.createIndex({ appId: 1, level: 1, time: -1 })

适合:

db.logs.find({
  appId: "pay",
  level: "ERROR",
  time: { $gte: start, $lt: end }
}).sort({ time: -1 })

等值字段先缩小范围,排序字段避免额外排序,范围字段通常放后面。

五、多键索引要注意数组膨胀

数组字段建索引会形成多键索引。例如:

db.articles.createIndex({ tags: 1 })

一篇文章多个标签,每个标签都会产生索引项。数组很大时,索引项数量也会膨胀。

多键索引适合标签、少量属性集合,但不适合无限增长的大数组。

六、索引的代价也很真实

索引会带来:

  • 额外磁盘空间;
  • 写入时维护索引;
  • 更新索引字段成本;
  • 内存缓存压力;
  • 建索引期间的资源消耗。

所以索引优化不是越多越好,而是让关键查询有合适索引,同时定期清理低价值索引。

七、常见误区与追问

查询形态推荐索引思路说明
等值过滤等值字段靠前先缩小扫描范围
等值 + 排序等值字段 + 排序字段避免额外 SORT
等值 + 范围等值字段 + 范围字段范围字段后续利用受限
数组字段谨慎多键索引数组元素会展开成多个索引项

记忆钩子:复合索引不是字段堆叠,而是查询路径的目录。等值先定位,排序接顺序,范围放后面收尾。

假设日志表每天 5000 万条,查询总是 appId + level + time range,索引 { appId: 1, level: 1, time: -1 } 能先按应用和级别收敛,再按时间扫描。若只建 { time: -1 },最近 1 小时所有应用日志都可能被扫描,再过滤 appIdlevel,成本会高很多。

  • 误区:给所有查询字段分别建单列索引就够了。 复合查询和排序通常需要复合索引,多个单列索引未必能同时满足过滤和排序。
  • 误区:复合索引字段顺序按字段重要性排。 字段顺序应按查询中的等值、排序、范围和选择性综合决定。
  • 误区:索引越多查询越快。 索引会增加写入维护、磁盘空间、内存压力和优化器选择成本。
  • 追问:最左前缀是什么意思? 复合索引通常要从最左字段开始连续使用,只有 { b: 1 } 很难利用 { a: 1, b: 1, c: 1 } 的前缀优势。
  • 追问:多键索引为什么要谨慎? 数组字段每个元素都可能生成索引项,数组越大,索引越膨胀,写入和查询成本都可能上升。
  • 追问:TTL 索引适合什么? 适合会话、临时 token、过期日志等按时间自动清理的数据,不适合需要复杂业务审批的删除流程。

八、加强记忆

MongoDB 索引设计的核心是“按查询建目录”。复合索引看最左前缀,字段顺序围绕等值、排序、范围来排;索引能减少扫描和排序,但会增加写入和空间成本。