我有一个记录集合,其中包含primary_id(唯一),secondary_id,状态字段。 ID是字母数字字段(例如'ABCD0000'),状态是数字(1-5)。 经常使用的查询之一是按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 } ]}
]}
关于什么是更好的索引或查询策略的任何建议?
答案 0 :(得分:0)
我会尝试2个索引
primary_id(状态)和secondary_id(状态)。
如果仍在发生超时,可以增加查询超时值吗? -考虑要尝试读取的大数据集。
如果这些索引没有帮助,并且期望获得良好的响应时间,那么您应该查看硬件限制-您的硬件是否足够好(请阅读mongodb的工作集大小)。如果确实需要关注性能并且您的数据量将不断增长,请扩大服务器/硬件的规模或查看分片。
OR-将状态2和3存储在单独的集合中,以减少查询时的“工作集大小”。