MongoDB 如何选择候选计划

How MongoDB Choose Candidate Plans

我的应用程序查询速度很慢。创建两个索引后,它在本地数据库中使用它们具有更好的性能。但是当我部署到生产数据库时,它仍然使用原始索引。

下面是我做的。

集合中的属性 tasksteam_idproject_idcreated_byassignee

查询如下所示

db.tasks.find({
  team_id: new ObjectId(teamId),
  $or: [
    {
      project_id: newObjectId(projectId),
      created_by: userId
    },
    {
      assignee: userId
    }
  ]
})

最初只有一个针对 team_id 的索引,它将检查 10k 多个文档。然后我添加了两个新索引

project_1_created_by_1: {
  project: 1,
  created_by: 1
}

assignee_1: {
  assignee: 1
}

在本地数据库中,我 运行 我的查询 explain({ verbose: true })。我可以看到 MongoDB 个已评估的索引

[
  QueryOptimizerCursor: [
    'project_1_created_by_1',
    'assignee_1',
  ],
  BtreeCursor: 'team_1'
]

终于QueryOptimizerCursor赢了。

但是当我 运行 生产时 MongoDB explain({ verbose: true }) 的结果显示它只评估了 team_1BasicCursor.

[
  BtreeCursor: `team_1`,
  BasicCursor
]

有没有人告诉我为什么 MongoDB 没有使用我创建的新索引,更糟糕的是它没有评估它。

PS:我可以确认新索引已在我的生产数据库中准备就绪,因为当我使用查询时 db.tasks.find({project: xxx, created_by:yyy}).explain() 它使用我创建的新索引。

已更新

production MongoDB 的版本是 2.4.12 而 local 是 2.6.7。当我在本地和 运行 安装新的 MongoDB 2.4.12 副本时,它使用 team 索引而不是 QueryOptimizerCursor.

相同的查询

不确定这是否只是因为 MongoDB 2.6.7 比 2.4.12 更智能。

如果集合中定义的多个索引可以满足查询,MongoDB 将并行测试所有适用的索引。可以 return 101 个结果的第一个索引将由查询计划程序 select 编辑。 selection 还有其他方面的索引,但根据 Query Optimization 文档,一般来说这是正确的。

此索引 selection 方法可能 select 一个次优索引。这是因为在 MongoDB 看来,您有多个索引描述同一事物。要减轻您观察到的次优指数 selection,您可以这样做:

  1. 删除所有其他您发现次优的索引。

    这是为了确保查询规划器除了选择您为查询量身定制的索引外别无选择。

  2. 使用hint()方法

    hint() 允许您明确告诉 MongoDB 使用规定的索引进行查询。例如:

    db.tasks.find(...).hint({project: 1, created_by: 1})
    

    有关 hint().

  3. 的更多信息,请参阅 https://docs.mongodb.com/v2.6/reference/operator/meta/hint/

查询中的另一个细微差别是它包含一个 $or 运算符。在这种情况下,$or 表达式中的每个术语都必须有一个与之关联的索引,否则MongoDB 将执行集合扫描(BasicCursor in MongoDB 2.6 个术语)。这在 https://docs.mongodb.com/v2.6/reference/operator/query/or/#behaviors

中有更详细的解释