【发布时间】:2019-09-01 03:18:00
【问题描述】:
我有一个记录集合,其中包含 primary_id(唯一)、secondary_id、status 字段等。 ID 是字母数字字段(例如“ABCD0000”),状态是数字 (1 - 5)。 经常使用的查询之一是按 id(相等或范围)和状态进行过滤。
例子:
- primary_id 介于 'ABCD0000' - 'ABCN0000' 之间且状态为 2 或 3 的记录,按 primary_id 排序。
- 在“ABCD0000”-“ABCD0000”之间的secondary_id 和状态为2 或3 的记录,按primary_id(或secondary_id,如果有帮助)排序。
过滤器中的状态主要是((2,3)中的状态)。
最初我们在每个字段上都有一个索引。但是当范围很大时查询会超时。我尝试添加多个索引(单个和复合)并使用不同的方式编写过滤器,但无法获得不错的性能。现在我有了这些索引:
[
{primary_id: 1},
{secondary_id: 1},
{status: 1},
{primary_id: 1, status: 1},
{status: 1, primary_id: 1},
{status: 1, secondary_id: 1}
]
此查询(对 primary_id 进行排序或不排序)
{ $and: [
{ primary_id: { $gte: 'ABCD0000' } },
{ primary_id: { $lte: 'ABCN0000' } },
{status: { $in: [2,3] } }
] }
使用以下计划:
...
"winningPlan" : {
"stage" : "FETCH",
"filter" : {
"status" : {
"$in" : [
2,
3
]
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"primary_id" : 1
},
"indexName" : "primary_idx",
"isMultiKey" : false,
"multiKeyPaths" : {
"primary_id" : [ ]
},
"isUnique" : true,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"primary_id" : [
"[\"ABCD0000\", \"ABCN0000\"]"
]
}
}
},
因此,如果返回的行数很大,则 FETCH 步骤似乎需要很长时间。令人惊讶的是,在运行初始状态测试时,primary_id 复合索引有时被选为获胜计划,而且速度非常快(几秒钟)。但由于某种原因,它不再被 Mongo 选中。我猜当查询需要按 primary_id 排序时,不会选择这个复合索引,正如我从 Mongo 文档中理解的那样
如果查询没有在排序规范之前或重叠的索引前缀上指定相等条件,则操作将无法有效地使用索引。
我尝试将查询更改如下,但仍未优化
{$or: [
{ $and: [ { primary_id: { $gte: 'ABCD0000' } }, { primary_id: { $lte: 'ABCN0000' } }, { status: 2 } ]},
{ $and: [ { primary_id: { $gte: 'ABCD0000' } }, { primary_id: { $lte: 'ABCN0000' } }, { status: 3 } ]}
]}
关于什么是更好的索引或查询策略有什么建议吗?
【问题讨论】:
标签: mongodb mongo-java mongodb-indexes