【问题标题】:C# Mongodb search through lookup is expensiveC# Mongodb 通过查找进行搜索很昂贵
【发布时间】:2020-12-23 13:22:33
【问题描述】:

我是 MongoDb 的新手,遇到性能问题。

我有 2 个集合,“A”和“B”
“A”有一个 _id 为“B”的列表(比如 50 个元素)

我想要实现的是通过查找“B”来查询“A”。

示例
假设 A 是口袋妖怪,B 是招式。
我想找到所有力量> = 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 并将清单作为 List BsonDocument 我使用 LinQ“ToList()”

【问题讨论】:

    标签: c# mongodb performance lookup database-performance


    【解决方案1】:

    这个聚合查询可能会更好一些,因为过滤是在加入端完成的。

    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"
             }
        }
    ])
    

    您还可以在{ power: 1}Moves 集合上添加一个索引,这将提高效率。

    但是,如果移动属于口袋妖怪,您可能需要重新考虑重新建模文档以减少相关性。然后只需将招式放在口袋妖怪文档中即可。

    【讨论】:

    • 您好,感谢您的评论。很难翻译你用 C# 写的东西,但我会试试看它是否更好。此外,我将尝试将“移动”作为“口袋妖怪”的子文档在您看来,拥有包含 50 个“移动”数组的“口袋妖怪”文档,其中每个移动有 20 个属性是一个好的文档模型?适合重度阅读操作吗?谢谢
    • 我在 A 数组中添加了 B 文档作为子文档。我添加了索引并做了和以前一样的事情 => $match { $gte : [ "$power", 30] } 但是获取信息所花费的时间与使用 $lookup 我想我正在做的一样这里出了点问题._.
    • 这似乎很奇怪,您可以在您的问题中发布您的文档的整个结构吗?如果可能的话,你能不能做一个.explain(),这样我们就可以看看发生了什么docs.mongodb.com/manual/reference/method/cursor.explain
    • @theramenboy 看起来可能是所有数据的序列化,您是否可以使用project 阶段将一些字段投影回来,看看您是否仍然有同样的问题?
    猜你喜欢
    • 2023-03-19
    • 2022-01-16
    • 2018-03-27
    • 1970-01-01
    • 2016-10-13
    • 1970-01-01
    • 1970-01-01
    • 2011-01-20
    • 2021-07-11
    相关资源
    最近更新 更多