MongoDB 如何选择候选计划
Posted
技术标签:
【中文标题】MongoDB 如何选择候选计划【英文标题】:How MongoDB Choose Candidate Plans 【发布时间】:2016-11-20 12:50:54 【问题描述】:我的应用程序中的查询速度很慢。创建两个索引后,它在本地数据库中使用它们以提高性能。但是当我部署在生产数据库上时,它仍然使用原始索引。
下面我做了什么。
集合中的属性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 更智能。
【问题讨论】:
【参考方案1】:如果集合中定义的多个索引可以满足查询,MongoDB 将并行测试所有适用的索引。查询计划器将选择第一个可以返回 101 个结果的索引。索引选择还有其他方面,但根据Query Optimization 文档,这通常是正确的。
这种索引选择方法可能会选择次优索引。这是因为从 MongoDB 的角度来看,您有多个索引来描述同一事物。为了减轻您观察到的次优索引选择,您可以执行以下操作:
删除您发现次优的所有其他索引。
这是为了确保查询计划者除了选择您为查询量身定制的索引之外别无选择。
使用hint()
方法
hint()
允许您明确告诉 MongoDB 使用规定的索引进行查询。例如:
db.tasks.find(...).hint(project: 1, created_by: 1)
有关hint()
的更多信息,请参阅https://docs.mongodb.com/v2.6/reference/operator/meta/hint/。
查询中的另一个细微差别是它包含$or
运算符。在这种情况下,$or
表达式中的每个术语都必须有一个与之关联的索引,否则 MongoDB 将执行集合扫描(在 MongoDB 2.6 术语中为BasicCursor
)。这在https://docs.mongodb.com/v2.6/reference/operator/query/or/#behaviors有更详细的解释
【讨论】:
感谢您的回答。我想我必须删除索引并发现最好的索引。再问一个问题,看来我只能通过hint()
指定一个索引,但我的$or
运算符不能使用多个索引。
hint()
只允许一个索引。在大多数情况下,最好删除不必要的索引,因为过多的索引可能会减慢您的插入速度,因为每次插入涉及索引项都意味着相应的索引也必须更新。以上是关于MongoDB 如何选择候选计划的主要内容,如果未能解决你的问题,请参考以下文章