Published on

Mongodb Index 优化实践

Authors
  • avatar
    Name
    Shelton Ma
    Twitter

1. Mongodb 索引优化过程

1. 复合索引顺序优化: 如何尽可能命中更多索引

  1. 首先创建一些组合索引/单列索引, 然后执行explain()

  2. queryPlanner中查看winningPlan是否符合预期, 如果在stage: 'IXSCAN', indexName:没有使用预期的索引, 说明说明不符合最优查询, 可以根据索引中各字段的分布规律/字段类型等特征排序

  3. 如果选择了一些更短的索引, 而不是选择命中最多的索引, 可以尝试将最多索引按照最短索引的顺序重新生成

  4. 如果mongodb发生索引误判, 可以强制执行来对比查询效果, 但不建议长期使用

    db.SecurityAlert.find({ attackStatus: 1, organization: "ABC" })
      .hint({ attackStatus: 1, organization: 1 })
      .explain("executionStats")
    

2. 查询优化器对大范围查询 (gte,gte, lte, $in) 可能直接选择全表扫描

3. 使用索引覆盖 (Covered Query), 确保索引包含查询字段和返回字段,避免回表 (fetch)

2. 背景介绍

Query Planner 选择最优索引,而非最多索引

MongoDB 的查询优化器 不会选取命中最多索引的查询计划,而是根据 查询代价 (Cost-Based Optimization, CBO) 选择执行效率最高的索引。即使某个查询命中了多个索引,它也可能只选用一个最优索引,甚至排除所有命中的索引,原因如下

  • 索引扫描成本:查询优化器计算索引扫描的扫描键数 (keysExamined) 和 返回文档数 (docsExamined),如果某个索引的扫描代价更低,即使它命中字段更少,MongoDB 也可能优先选择它。
  • 索引覆盖率:如果某个索引可以 覆盖查询 (covered query),MongoDB 更倾向于使用它,而不是命中多个索引但仍需回表 (fetch documents) 的情况。
  • 查询的选择性 (Selectivity):
    • 高选择性:如果索引能大幅减少查询结果集(如 { field: 1 } 索引在 field=5 仅返回 1% 的数据),则 MongoDB 更倾向于使用它。
    • 低选择性:如果索引返回的数据量太大(如 field: { $gt: 1 } 返回 90% 数据),MongoDB 可能会选择全表扫描 (COLLSCAN) 而排除所有索引。