MongoDB 如何选择候选计划

Sha*_* Xu 4 mongodb mongodb-indexes

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

下面是我所做的。

集合中的属性tasksteam_idproject_idcreated_byassignee等。

查询如下所示

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

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

project_1_created_by_1: {
  project: 1,
  created_by: 1
}

assignee_1: {
  assignee: 1
}
Run Code Online (Sandbox Code Playgroud)

在本地数据库中,我使用explain({ verbose: true }). 我可以看到 MongoDB 评估的索引

[
  QueryOptimizerCursor: [
    'project_1_created_by_1',
    'assignee_1',
  ],
  BtreeCursor: 'team_1'
]
Run Code Online (Sandbox Code Playgroud)

终于QueryOptimizerCursor赢了。

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

[
  BtreeCursor: `team_1`,
  BasicCursor
]
Run Code Online (Sandbox Code Playgroud)

有谁给我一些信息为什么 MongoDB 不使用我创建的新索引,更糟糕的是它没有评估它。

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

更新

生产MongoDB的版本是2.4.12,本地版本是2.6.7。当我在本地安装 MongoDB 2.4.12 的新副本并运行相同的查询时,它使用team索引而不是QueryOptimizerCursor.

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

kev*_*adi 5

如果集合中定义的多个索引可以满足查询,MongoDB 将并行测试所有适用的索引。第一个可以返回 101 个结果的索引将由查询规划器选择。索引选择还有其他方面,但根据查询优化文档,一般来说这是正确的。

该索引选择方法可能会选择次优索引。这是因为从 MongoDB 的角度来看,您有多个描述同一事物的索引。为了减轻您观察到的次优索引选择,您可以执行以下操作:

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

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

  2. 使用hint()方法

    hint()允许您显式告诉 MongoDB 使用指定的索引进行查询。例如:

    db.tasks.find(...).hint({project: 1, created_by: 1})
    
    Run Code Online (Sandbox Code Playgroud)

    请参阅https://docs.mongodb.com/v2.6/reference/operator/meta/hint/了解有关 的更多信息hint()

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