云数据库 MongoDB 聚合查询优化建立复合索引的核心是让索引字段顺序匹配聚合管道中的 `$match` 过滤条件和 `$sort` 排序字段。适用场景为读多写少的查询业务,风险边界在于索引过多会降低写入性能并增加存储空间。
先说结论:建立复合索引需遵循“等值优先、排序在后”原则,确保聚合管道早期阶段命中索引。
- 先定位:通过执行计划确认慢查询集中在 `$match` 还是 `$sort` 阶段。
- 先做:按照查询条件的过滤优先级调整索引字段顺序,等值查询字段排在范围查询字段之前。
- 再验证:使用 explain 命令检查是否出现 IXSCAN 而非 COLLSCAN,确认扫描文档数下降。
命令速用版
在 MongoDB Shell 或客户端工具中,使用 createIndex 命令创建复合索引,字段顺序对应查询条件频率。
db.collection.createIndex({ "status": 1, "createTime": -1 })上述命令针对 status 等值查询且按 createTime 排序的场景,status 字段放在索引第一位。
为什么会这样
复合索引生效的关键在于索引字段顺序与查询谓词的匹配度。
MongoDB 查询优化器在使用复合索引时遵循最左前缀原则,如果索引定义为 {A: 1, B: 1},查询条件只包含 B 则无法使用该索引。在聚合管道中,$match 和 $sort 阶段位于管道越靠前,索引带来的过滤效果越明显,能减少后续阶段处理的数据量。
分步处理
第一步:分析聚合管道结构,提取 $match 中的过滤字段和 $sort 中的排序字段。
第二步:确定字段顺序,将等值匹配字段放在复合索引左侧,范围查询或排序字段放在右侧。
第三步:在业务低峰期执行创建索引命令,避免锁竞争影响线上写入。
第四步:检查索引创建状态,确保状态为 ready 而非 building。
怎么验证是否生效
使用 explain 方法查看聚合查询的执行计划,关注执行阶段和扫描数量。
db.collection.aggregate([...]).explain("executionStats")检查输出中的 executionStats 部分,若 totalDocsExamined 明显小于 nReturned,且 inputStage 显示为 IXSCAN,说明索引生效。若显示 COLLSCAN,则表示进行了全集合扫描,索引未命中。
常见坑
索引字段顺序错误会导致索引失效,例如将范围查询字段放在等值查询字段之前。
对数组字段建立索引时,复合索引的行为可能与预期不同,需单独测试。
过度建立复合索引会占用磁盘空间并拖慢写入速度,单个集合索引数量建议控制在合理范围内。
常见问题
复合索引字段顺序可以随意调整吗?
不可以,字段顺序直接影响索引能否命中,需根据查询条件的选择性调整。
聚合管道中的 $group 阶段能利用索引吗?
通常不能直接利用索引加速分组,但前置的 $match 命中索引可减少进入 $group 的数据量。
建立索引会影响数据库写入性能吗?
会,每次写入都需要更新索引树,索引越多写入开销越大。
参考来源
- MongoDB Official Documentation, "Indexes", https://www.mongodb.com/docs/manual/indexes/
- MongoDB Official Documentation, "Aggregation Pipeline", https://www.mongodb.com/docs/manual/aggregation/