问题描述
我是MongoDb的新手,并且遇到性能问题。
我有2个收藏集,“ A”和“ B”
“ A”具有一个列表,其_id为“ B”(例如50个元素)
示例:
假设A是神奇宝贝,B是Moves。
我想找到所有动力大于等于30的宠物小精灵
我所做的就是这样:
db.collection("pokemon")
.aggregate()
.lookup("Moves","moves.move_id","_id","full_moves")
.match({ $gte: { "full_moves.power": 30 }})
(这里的代码是一个示例,不是C#,但我在C#中也做同样的事情)
通过我的结构,它可以正常工作,我得到了想要的。
但是性能太差了。
如果我用Skip(n)和Limit(n + 20)限制结果,则需要2秒来执行聚合。
如果我不这样做,则大约需要28秒来执行完整查找。
我做的对吗?还有其他办法吗?
我知道我应该把文档“ B”作为“ A”的子文档,但是“ B”很大,并且“ A”与“ B”有50种关系,我认为这不是一条合适的路径。
谢谢
修改
这里的Pkm文档结构(不是确切的,我只是在玩弄以了解mongodb)
口袋妖怪
{
"_id": ObjectId(''),"abilities": [
{
//Simple object with 3 props
}
],"experience": 64,"forms": [
{
//Simple object with 5 props
}
],"height": 7,"id": 1,"is_default": true,"moves": [ //a pokemon can have like 50 moves
{
//Complex object with like 20 properties,some are Array but for search purpose I use only not nested properties like power,name etc
}
],"name": "bulbasaur","stats": {
"hp": 0,"attack": 0,"defense": 0,"special-attack": 0,"special-defense": 0,"speed": 0
},"types": [
{
//simple object with 2 properties
}
],"weight": 50
}
我还使用说明在MongodbCompass中运行过滤器,它说对于集合来说,查询操作({“ moves.move.power”:{$ gte:30}}花费了4毫秒
{
"stage": "FETCH","nReturned": 942,"executionTimeMillisEstimate": 4,"works": 12179,"advanced": 942,"needTime": 11236,"needYield": 0,"saveState": 12,"restoreState": 12,"iSEOF": 1,"docsexamined": 942,"alreadyHasObj": 0
}
那么可能这里的问题是这些数据的表现形式?
我将C#最新驱动程序用于mongodb,并将清单BsonDocument用作清单,我使用LinQ“ ToList()”
解决方法
此聚合查询可能会更好一些,因为过滤是在联接端进行的。
db.pokemon.aggregate([
{
$lookup:
{
from: "Moves",let: { move_id: "$moves.move_id" },pipeline: [
{ $match:
{ $expr:
{ $and:
[
{ $gte: [ "$power",30 ] },{ $eq: [ "$_id","$$move_id" ] }
]
}
}
}
],as: "full_moves"
}
}
])
然后,您还可以在Moves
的{{1}}集合上添加索引,这将使索引效率更高。
但是,如果这些举动属于口袋妖怪,那么您可能需要重新考虑重新建模文档以减少关联。然后将动作放在口袋妖怪文档中。