1. 创建合适的索引类型
根据查询模式选择索引类型是优化基础。单字段索引适用于频繁查询的单个字段(如db.collection.createIndex({ userid: 1 }));复合索引针对多条件查询,需将选择性高(唯一值多)的字段放在前面(如db.collection.createIndex({ userid: 1, status: -1 }),其中userid的选择性高于status);覆盖索引确保查询的所有字段都在索引中,避免访问文档(如索引包含{ field1: 1, field2: 1 },查询仅需这两个字段时可不用回表);此外还有文本索引(全文搜索)、地理空间索引(地理位置查询)等特殊类型。
2. 利用explain()分析查询计划
通过explain("executionStats")查看查询是否使用索引、索引使用效果及执行成本。重点关注winningPlan中的inputStage.stage(若为IXSCAN表示使用索引,COLLSCAN表示全表扫描)、executionStats.executionTimeMillis(执行时间)、totalDocsExamined(扫描文档数)等指标,判断索引有效性。
3. 监控与清理索引使用情况
使用getIndexes()查看集合所有索引,db.collection.aggregate([{ $indexStats: {} }])监控索引使用频率(accesses.ops表示使用次数,accesses.since表示上次统计时间)。定期删除未使用或冗余的索引(如不再查询的字段索引、重复的复合索引),减少写操作开销(插入、更新、删除时需维护索引)。
4. 优化复合索引字段顺序
复合索引的字段顺序直接影响查询性能。应将选择性高(过滤后剩余文档少)且查询频率高的字段放在前面。例如,查询条件常为{ userid: 123, status: 'active' },且userid的选择性远高于status,则复合索引应为{ userid: 1, status: 1 },避免因顺序不当导致索引无法命中。
5. 定期维护索引碎片
随着数据增删改,索引会产生碎片,降低查询效率。使用reIndex()命令重建索引(如db.collection.reIndex()),整理索引碎片,提升索引访问速度。注意:重建索引会锁表(MongoDB 4.0+支持并发重建部分索引),建议在低峰期操作。
6. 避免过度索引
每创建一个索引都会增加写操作的开销(插入、更新、删除时需同步更新索引),并占用更多磁盘空间。优先为高频查询、过滤条件严格的字段创建索引,删除无用索引(如测试阶段创建的临时索引、不再使用的字段索引),平衡查询性能与写入开销。
7. 使用覆盖索引减少IO
设计查询时,尽量让查询字段包含在索引中,实现覆盖查询(即查询无需访问文档本身)。例如,索引为{ userid: 1, name: 1 },查询db.collection.find({ userid: 123 }, { _id: 0, userid: 1, name: 1 })可直接从索引获取数据,无需读取文档,显著减少磁盘IO。
8. 强制使用指定索引
若查询优化器未选择最优索引,可使用hint()方法强制指定索引。例如,db.collection.find({ userid: 123, status: 'active' }).hint({ userid: 1, status: 1 })强制使用{ userid: 1, status: 1 }索引。适用于查询优化器因统计信息不准确选择低效索引的场景。