MongoDB已用索引但聚合查询仍缓慢,索引是否创建错误?
MongoDB聚合查询慢:索引顺序优化方案
问题概述
transaction集合含600万条记录,已创建指定复合索引,但执行聚合查询时耗时30-60秒——虽命中索引,但性能未达预期,核心问题出在索引字段顺序不合理。
当前索引
创建语句:
db.transaction.createIndex({ type: 1, 'reimbursement.reimbursement_vendor': 1, 'reimbursement.status': 1, 'reimbursement.employee_note': 1, company_id: 1, created: 1 })
慢查询语句
db.transaction.aggregate([ { $match: { type: 'card', company_id: 'google', 'reimbursement.reimbursement_vendor': { $ne: null }, 'reimbursement.status': { $in: ['approved', 'completed'] }, 'reimbursement.employee_note': { $nin: [null, ''] }, created: { $gte: new ISODate('2022-08-12') }, }, }, { $sort: { created: 1 } }, { $limit: 1 }, ]);
性能瓶颈分析(基于Explain结果)
从winningPlan可见:
- 查询流程为
IXSCAN → SORT → FETCH,说明需要先扫描所有符合过滤条件的文档,再在内存中全局排序后取第一条——这是耗时的核心原因。 - 索引顺序违背MongoDB索引优化原则:
- 等值匹配字段
company_id被放在3个非等值过滤字段(reimbursement相关字段)之后,非等值条件($ne/$in/$nin)会大幅扩大索引扫描范围,无法利用前缀匹配缩小有效区间。 - 排序字段
created位于索引末尾,无法直接通过索引按created:1顺序读取数据,必须加载大量文档到内存排序,对600万条记录的集合来说,这个操作开销极大。
- 等值匹配字段
优化方案:调整索引字段顺序
创建符合等值过滤优先 → 排序字段 → 其他过滤字段原则的新索引:
db.transaction.createIndex({ type: 1, company_id: 1, created: 1, 'reimbursement.reimbursement_vendor': 1, 'reimbursement.status': 1, 'reimbursement.employee_note': 1 })
优化逻辑
- 等值字段前置:
type和company_id是精确匹配条件,放在最前面让MongoDB快速定位到索引的精准区间,减少初始扫描范围。 - 排序字段紧跟:
created:1作为排序字段放在等值字段之后,索引本身会按created升序排列,查询时可直接按顺序扫描,找到第一个符合后续过滤条件的文档,彻底消除全局排序步骤。 - 过滤字段后置:
reimbursement相关字段放在最后,在索引层面进一步过滤不符合条件的条目,减少回表(FETCH)的文档数量。
验证与清理
- 新索引生效后,用
explain()验证查询流程,预期会变为IXSCAN → FETCH,无SORT阶段,耗时会大幅降低。 - 若原索引不再被其他查询使用,建议删除以节省存储和写入开销:
db.transaction.dropIndex('type_1_reimbursement.reimbursement_vendor_1_reimbursement.status_1_reimbursement.employee_note_1_company_id_1_created_1')
内容的提问来源于stack exchange,提问作者bigpotato
相关产品推荐
相关产品推荐

