我有一个记录集合,其中包含primary_id(唯一),secondary_id,状态字段等。ID 是字母数字字段(例如"ABCD0000"),状态是数字 (1 - 5)。 经常使用的查询之一是按 id(相等或范围)和状态进行筛选。
例子:
- primary_id介于"ABCD0000"-"ABCN0000"和状态为 2 或 3 之间的记录,按primary_id排序。
- secondary_id介于"ABCD0000"-"ABCD0000"和状态为 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复合索引有时会被选为获胜计划,而且速度超快(几秒钟)。但由于某种原因,它不再被蒙戈选中了。我想当查询需要按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 } ]}
]}
关于什么是更好的索引或查询策略的任何建议?
我会尝试使用 2 个索引
primary_id,状态和secondary_id,状态。
如果超时仍在发生,是否可以增加查询超时值? - 考虑您尝试从中读取的大型数据集。
如果这些索引没有帮助并且预期有良好的响应时间,那么您应该查看硬件约束 - 您的硬件是否足够好(阅读mongodb的工作集大小)。要么扩展服务器/硬件,要么查看分片,如果性能确实是一个问题并且您的数据大小将会增长。
OR - 将状态 2 和 3 存储在单独的集合中,以便在查询它们时减少"工作集大小"。