MongoDB#聚合管道优化

聚合管道优化

  • 一些 聚合操作的优化思路,可以提高聚合速度

投影优化

  • 即在投影阶段,$project $unset $set $addFields,可以限定时返回需要的字段,而非完整的文档所有的字段,以此减少通过管道的数据量。

管道序列优化

( p r o j e c t / project/ project/unset/ s e t / set/ set/addFields) + $match序列优化

  • 对于此类投影阶段后面带有 m a t c h 的 聚 合 管 道 , m o n g o d b 通 过 将 match的聚合管道,mongodb通过将 matchmongodbmatch阶段中包含不需要在此投影阶段计算的值的筛选器移动到此投影阶段之前的 m a t c h 阶 段 , ∗ ∗ ∗ 即 将 一 个 match阶段,***即将一个 matchmatch的多个筛选器拆分成多个$match***

  • 示例:

    { $addFields: {
        maxTime: { $max: "$times" },
        minTime: { $min: "$times" }
    } },
    { $project: {
        _id: 1, name: 1, times: 1, maxTime: 1, minTime: 1,
        avgTime: { $avg: ["$maxTime", "$minTime"] }
    } },
    { $match: {
        name: "Joe Schmoe",
        maxTime: { $lt: 20 },
        minTime: { $gt: 5 },
        avgTime: { $gt: 7 }
    } }
    

    上面的管道可以优化为:

    { $match: { name: "Joe Schmoe" } },
    { $addFields: {
                    maxTime: { $max: "$times" },
            minTime: { $min: "$times" }
    } },
    { $match: { maxTime: { $lt: 20 }, minTime: { $gt: 5 } } },
    { $project: {
            _id: 1, name: 1, times: 1, maxTime: 1, minTime: 1,
            avgTime: { $avg: ["$maxTime", "$minTime"] }
    } },
    { $match: { avgTime: { $gt: 7 } } }
    

    $match过滤器{ avgTime: { KaTeX parse error: Expected 'EOF', got '}' at position 7: gt: 7 }̲ }取决于project阶段来计算avgTime字段。 p r o j e c t 阶 段 是 此 管 道 中 的 最 后 一 个 投 影 阶 段 , 因 此 a v g T i m e 上 的 project阶段是此管道中的最后一个投影阶段,因此avgTime上的 projectavgTimematch过滤器无法移动。
    maxTime和minTime字段在 a d d F i e l d s 阶 段 计 算 , 但 不 依 赖 于 addFields阶段计算,但不依赖于 addFieldsproject阶段。优化器为这些字段上的过滤器创建了一个新的 m a t c h 阶 段 , 并 将 其 放 在 match阶段,并将其放在 matchproject阶段之前。
    m a t c h 过 滤 器 n a m e : " J o e S c h m o e " 不 使 用 在 match过滤器{ name: "Joe Schmoe" }不使用在 matchname:"JoeSchmoe"使project或 a d d F i e l d s 阶 段 计 算 的 任 何 值 , 因 此 它 在 两 个 投 影 阶 段 之 前 被 移 动 到 新 的 addFields阶段计算的任何值,因此它在两个投影阶段之前被移动到新的 addFieldsmatch阶段。

    优化后,过滤器{ name: “Joe Schmoe” }位于管道开头的$match阶段。这具有额外的好处,即允许聚合在最初查询集合时在name字段上使用索引

$sort + $match序列优化

  • $match 阶段需要在 $sort 阶段前面,以此来减少需要排序的文档的数量。

$redact + $match序列优化

  • 当 $match 阶段在 $redact 阶段之后时,可以在 $redact 阶段之前添加 m a t c h 的 一 部 分 来 优 化 , 如 果 match 的一部分来优化,如果 matchmatch处于管道的最前方,还可以使用索引来提高效率;

  • { $redact: { $cond: { if: { $eq: [ "$level", 5 ] }, then: "$$PRUNE", else: "$$DESCEND" } } },
    { $match: { year: 2014, category: { $ne: "Z" } } }
    

    优化为:

    { $match: { year: 2014 } },
    { $redact: { $cond: { if: { $eq: [ "$level", 5 ] }, then: "$$PRUNE", else: "$$DESCEND" } } },
    { $match: { year: 2014, category: { $ne: "Z" } } }
    

$project/ $unset + $skip序列优化

  • 当 $project u n s e t 阶 段 之 后 有 unset阶段之后有 unsetskip时,应当使 s k i p 处 在 skip处在 skipproject/$unset阶段之前

管道聚合优化

  • 在优化了管道内序列的排序后,管道聚合优化通常会进行阶段之间合并的操作

$sort + $limit 合并

  • { $sort : { age : -1 } },
    { $project : { age : 1, status : 1, name : 1 } },
    { $limit: 5 }
    

    修改为:

    {
        "$sort" : {
           "sortKey" : {
              "age" : -1
           },
           "limit" : NumberLong(5)
        }
    },
    { "$project" : {
             "age" : 1,
             "status" : 1,
             "name" : 1
      }
    }
    
  • 但是在实际测试中,我发现有一些mongo server并不支持这样的合并操作。

$limit + $limt 合并

  • 当一个limit阶段紧跟着另一个limit阶段的时候,可以合并为一个,限制量为初始两个限制量的较小的那一个值。

$skip + $skip 合并

  • 当一个skip阶段紧跟着另一个skip阶段的时候,可以合并为一个,新的跳过量为初始两个跳过量的和。

$match + $match 合并

  • 当一个 match 阶段紧随另一个 match阶段的时候,两个match阶段可以合并为一个。

$lookup + $unwind 合并

  • 当 unwind阶段后面是 lookup阶段,并且在 unwind阶段运行时,优化程序可以将其合并到阶段内,避免创建较大的文档。

  • {
      $lookup: {
        from: "otherCollection",
        as: "resultingArray",
        localField: "x",
        foreignField: "y"
      }
    },
    { $unwind: "$resultingArray"}
    

聚合管道的限制

结果大小限制

  • 聚合命令返回一个游标或者将结果存储在集合之中,结果集中每个文档收到BSON文件大小限制,16M字节,如果单个文档大小超出这个限制,那么命令将发生错误。该限制仅适用于返回的文件,但是在管道处理期间,文档可能超过这个大小限制。

Memory限制

  • 管道阶段的RAM限制为100M(100x1024x1024字节)(RAM限制是最终用户对台式机,笔记本电脑或其他类型的计算机设备中内置的总随机存取存储器的访问程度),如果某个阶段超出这个限制,会导致错误。如果要允许处理大数据集,可以在aggregate()方法中设置allowDiskuse选项。
  • allowDiskuse允许大多数聚合管道操作将数据写入临时文件,一下操作则是 allowDiskuse选项的例外
    • $graphLookup阶段
    • g r o u p 阶 段 中 使 用 的 group阶段中使用的 group使addToset累加器表达式
    • g r o u p 阶 段 使 用 的 group阶段使用的 group使push累加器表达式

你可能感兴趣的:(MongoDB,mongodb,数据库,database)