我在mongodb集合中有以下格式的数据:
{
_id: ObjectId,
Product: string,
Modules: [
{
StaticModuleId: Int64,
Set: [
{
k: Int64,
v: {
Value: Double,
AnotherId: Int64
}
},
...
]
},
...
]
}
这是我的名为MyIndex的索引:
{
Product: 1,
'Modules.StaticModuleId': 1,
'Modules.Set.k': 1,
'Modules.Set.v.Value': 1
}
该集合中有5个文档,每个文档中有10个模块和100个元素,总共50个模块和5000个条目。然后我运行了这个查询:
{
'Product': 'Test',
$and: [
{
'Modules.StaticModuleId': 2010220,
'Modules.Set': {
$elemMatch: {
k: 41439,
'v.Value': 2186233
}
}
},
{
'Modules.StaticModuleId': 2010226
},
{
'Modules.StaticModuleId': 2010228
}
]
}
这是.explain():
{
cursor: 'BtreeCursor MyIndex',
isMultiKey: true,
n: 4,
nscannedObjects: 941,
nscanned: 941,
nscannedObjectsAllPlans: 941,
nscannedAllPlans: 941,
scanAndOrder: false,
indexOnly: false,
nYields: 0,
nChunkSkips: 0,
millis: 52
}
当我继续添加额外的$ elemMatch子句时,性能会降低到> 200毫秒。这种类型的查询是否可转换,如果是,那么我是如何改进性能的?
答案 0 :(得分:1)
尝试删除上一个索引并使用这样的多键标志创建:
db.collection.ensureIndex({{'Product':1, 'Modules.StaticModuleId':1, 'Modules.Set':1, 'Modules.Set.k':1, 'Modules.Set.v.Value':1}, {multikey:true})
在我的测试用例中,我只有100个scaned对象而millis = 0
提示:您可以通过以下方式将数据和/或索引加载到内存中:
db.runCommand({ touch: "collection", data: true, index: true })
我使用下一个脚本来重现问题和数据准备:
for(var prod=0; prod<1000; prod++) {
prodObj={Product:"product" + prod};
modObj=[];
for(var mod=0; mod < 10; mod++) {
seObj=[];
for(var se=0; se < 100; se++) {
seObj[se] = {k: "Int64-" + se, v:{Value:"Double-" + se}, AnotherId:"Int64"};
}
modObj[mod]={StaticModuleId:"Int64-"+prod, Set:seObj};
}
prodObj.Modules=modObj;
db.so.insert(prodObj);
}
可能这对你的任务不正确
答案 1 :(得分:0)
我认为数据模型并不是那么好。这是一种类似模特的关系。如果您可以将数据模型更改为简单:
{
Product: "string",
StaticModuleId: "string",
Set:
[
{
k: "string",
v:
{
Value: "double",
AnotherId: "string"
}
}
]
}
您将获得更好的性能和更低的复杂性