我的应用程序中查询速度很慢。创建两个索引后,它使用它们在本地数据库中具有更好的性能。但是当我在生产数据库上部署时,它仍然使用原始索引。
在这之下我做了什么。
集合tasks
中的属性:team_id
,project_id
,created_by
和assignee
等。
查询如下所示
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_1
和BasicCursor
。
[
BtreeCursor: `team_1`,
BasicCursor
]
有没有人给我一些信息,说明为什么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更聪明。
答案 0 :(得分:2)
如果集合中定义的多个索引可以满足查询,MongoDB将并行测试所有适用的索引。查询计划程序将选择可返回101结果的第一个索引。索引选择还有其他方面,但总的来说,根据Query Optimization文档确实如此。
该索引选择方法可以选择次优索引。这是因为从MongoDB的角度来看,你有多个描述相同内容的索引。要减轻您观察到的次优索引选择,您可以执行以下操作:
删除您发现的次优的所有其他索引。
这是为了确保查询计划程序除了选择为查询定制的索引之外别无选择。
使用hint()
方法
hint()
允许您明确告诉MongoDB使用规定的索引进行查询。例如:
db.tasks.find(...).hint({project: 1, created_by: 1})
有关hint()
。
您的查询中的另一个细微差别是它包含$or
运算符。在这种情况下, $or
表达式中的每个术语都必须具有与之关联的索引,否则MongoDB将执行MongoDB 2.6术语中的集合扫描(BasicCursor
)。这在https://docs.mongodb.com/v2.6/reference/operator/query/or/#behaviors