我有一个具有以下索引的 MongoDB 集合项:
db.items.createIndexes([{ team: 1, a: 1 }, { team: 1, b: 1 }])
我插入了一些这样的测试数据:
db.items.insertMany([
{ team: 1, a: "valueA1" },
{ team: 1, a: "valueA2" },
{ team: 1, a: "valueA3" },
]);
我有一个类似于以下内容的 MongoDB 查询:
db.items.find({
team: [teamId],
// dynamic query part
$or: [{ a: [value] }, { b: [value] }]
})
我的目标是确保查询始终使用 team_1_a_1 和 team_1_b_1 索引,但实际索引选择会根据查询值和查询的动态部分而变化。
例如,当我运行以下查询时:
db.items.find({
team: 1,
$or: [{ a: "valueA1" }, { b: "valueB1" }]
}).explain("queryPlanner")
我得到了使用两个索引的预期结果:
"winningPlan": {
"stage": "FETCH",
"inputStage": {
"stage": "OR",
"inputStages": [
{
"indexName": "team_1_a_1",
...
},
{
"indexName": "team_1_b_1",
...
}
]
}
}
但是,对于此查询:
db.items.find({
team: 2,
$or: [{ a: "valueA1" }, { b: "valueB1" }]
}).explain("queryPlanner")
结果与我的预期不符:
"winningPlan": {
"stage": "FETCH",
"inputStage": {
"stage": "IXSCAN",
"indexName": "team_1_a_1",
...
}
}
我了解 MongoDB 有时会自动选择更好的索引。但在我的用例中,我有超过 1 亿个文档,索引选择存在性能问题,并且经常遇到以下错误:
multiplanner encountered a failure while selecting best plan :: caused by :: operation exceeded time limit
我正在寻找一种方法来强制 MongoDB 始终在 $or 子句中使用索引,类似于hint的工作方式,并跳过 MongoDB 的索引选择过程。关于如何实现这一目标有什么建议吗?
你可以尝试改变索引键的顺序吗?
db.items.createIndexes([{ a: 1, team : 1 }, { b: 1, team: 1 }])
在这种情况下,因为两个索引都有前缀键:team,所以Mongo将进行自动选择过程。 如果我们反转键以在前缀处指定 $or 的过滤键,那么 mongo 将知道并选择正确的索引。