

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 查询计划器 v3
<a name="query-planner-v3"></a>

亚马逊 DocumentDB 8.0 中的 Planner 版本 3 支持 21 个聚合阶段，包括 6 个新阶段。Planner V3 内置了对不同命令的支持。与亚马逊 DocumentDB 5.0 中的 Planner v2 相比，它的总体性能提高了多达 2 倍。亚马逊 DocumentDB 8.0 中的所有新功能和运算符都与 Planner v3 兼容。Planner v3 支持的亚马逊 DocumentDB 8.0 中新的聚合阶段包括 \$1replaceWith、\$1VectorSearch、\$1merge、\$1set、\$1unset、\$1unset、\$1bucket。Planner v3 还支持亚马逊 DocumentDB 8.0 中的新功能和运算符，包括排序规则、视图、\$1merge、\$1pow、\$1rand、\$1dateTrunc、\$1、\$1、\$1。dateToParts dateFromParts

**Topics**
+ [先决条件](#nqp-prerequisites)
+ [选择计划器版本 3.0 作为默认查询计划器](#second-concept-chapter)
+ [最佳实践](#nqp-best-practices)
+ [限制](#nqp-limitations)
+ [改进了 `aggregate` 和 `distinct` 运算符](#operator-improvements)
+ [计划器版本 1.0、3.0 和 MongoDB 之间的潜在行为差异](#planner-behavior-differences)

## 先决条件
<a name="nqp-prerequisites"></a>

以下先决条件适用于计划器版本 3.0：
+ Planner 版本 3.0 适用于所有提供引擎版本 8.0 的区域。
+ 选择引擎版本 8.0 时，Planner 版本 3.0 是默认的查询计划器。

## 选择计划器版本 3.0 作为默认查询计划器
<a name="second-concept-chapter"></a>

如果您在 Amazon DocumentDB 8.0 中更改了默认查询计划器，并且需要恢复到计划器 v3，则可以通过控制台或 CLI 进行操作：
+ 按照 [修改 Amazon DocumentDB 集群参数](cluster_parameter_groups-parameters.md) 中的步骤修改集群的参数组。
+ 对于名为 “PlannerVersion” 的参数，将值更改为 3.0，表示计划器版本 3.0。
+ 选择**立即应用**（若选择**重启时应用**，则在集群下次重启后才会生效）。

## 最佳实践
<a name="nqp-best-practices"></a>

要获得预期结果，请在应用 Planner 版本 3.0 时使用以下最佳实践：
+ 在全局群集中，在两个区域的群集参数组中选择相同的`plannerVersion`值（1.0、2.0 或 3.0）。请注意，在主要区域和辅助区域中选择不同的计划程序版本可能会导致查询行为和性能不一致。
+ 在计划维护时段或流量减少期间更新到计划器版本 3.0 的干扰最小，因为如果在工作负载活跃运行时更改计划器版本，则错误率可能会增加。

## 限制
<a name="nqp-limitations"></a>

以下限制适用于计划器版本 3.0：
+ 弹性集群不支持 Planner 版本 3.0，它将退回到计划器版本 1.0。
+ 虽然 Planner v1 允许使用 “PlanHint” 来确保查询优化器选择特定的查询计划，但 Planner v3 不允许使用 “PlanHint”，而是依靠内部优化来为给定查询选择最佳计划。

## 改进了 `aggregate` 和 `distinct` 运算符
<a name="operator-improvements"></a>

Planner 版本 3.0 引入了对 \$1聚合阶段和 \$1distinct 命令的改进。以下是一些最值得注意的改进。
+ 如果可能，计划器会将\$1match阶段移到流程的更早阶段，从而减少后续阶段处理的文档数量。

  ```
  //Planner v1
  db.orders.aggregate([
    { $project: { customerId: 1, orderDate: 1, totalAmount: 1 } },
    { $match: { customerId: { $gt: 1000 } } }
  ])
  
  // Planner v3 pulls up the match since customerId exists in original documents
  // Optimized internally as:
  db.orders.aggregate([
    { $match: { customerId: { $gt: 1000 } } },  // Pulled up before project
    { $project: { customerId: 1, orderDate: 1, totalAmount: 1 } }
  ])
  ```
+ 当\$1lookup和\$1unwing阶段在同一字段上操作时，规划器会自动将它们组合在一起，从而减少中间数据处理并提高性能。

  ```
                   Example query:
  //Planner v1
  db.orders.aggregate([
    { $lookup: { from: "products", localField: "productId", foreignField: "_id", as: "productInfo" } },
    { $unwind: "$productInfo" },
    { $project: { orderDate: 1, "productInfo.name": 1, "productInfo.price": 1 } }
  ])
  
  // Planner version 3.0 optimizes this internally by coalescing the $lookup and $unwind stages
  ```
+ Planner 版本 3.0 引入了一种新的 Distinct Scan 执行策略，该策略可显著提高低基数索引上不同操作的性能。

  ```
                   Example query:
  //// If there is a low cardinality index on "category", you may see a query plan like below
  db.explain().products.distinct("category")
  
  "queryPlanner" : {
          "plannerVersion" : 3,
          "namespace" : "db.products",
          "winningPlan" : {
                  "stage" : "AGGREGATE",
                  "inputStage" : {
                          "stage" : "DISTINCT_SCAN",
                          "inputStage" : {
                                  "stage" : "IXONLYSCAN",
                                  "indexName" : "category_1",
                                  "direction" : "forward"
                          }
                  }
          }
  }
  ```

## 计划器版本 1.0、3.0 和 MongoDB 之间的潜在行为差异
<a name="planner-behavior-differences"></a>

在某些边缘情况下，计划器版本 3.0 可能产生的结果与计划器版本 1.0 略有不同。本节将介绍这些可能性的一些示例。

------
#### [ Feature Differences ]
+ 在空集合中，或者当之前的阶段（例如匹配筛选所有文档）时，Planner v1 会给出输出 “字段”: 0。Planner v3 和 MongoDB 不会给出任何输出。
+ 在 Plannerv1 中，如果上一阶段返回的文档少于 n 个，\$1“\$1skip”: n\$1 不会跳过。无论返回的文档数量如何，Plannerv3 和 MongoDB 都能正确跳过。
+  当 \$1lookup 中引用的外来集合不存在时，plannerv1 会引发错误。Planner v3 和 MongoDB 将外来集合视为空集合并执行 \$1lookup。

  ```
  db.coll.aggregate([
      {$lookup: {from: "does_not_exist", localField: "a", foreignField: "a", as: "c"}}
  ])
  ```
+  只有 Planner v1 允许在管道中使用多个 \$1search Planner v2/v3 会抛出错误，而 MongoDB 不支持它。

  ```
  VectorSearch = { "$search": { "vectorSearch": {
     "vector": [0.2, 0.5, 0.8], 
     "path": "vectorEmbedding", 
     "similarity": "cosine", 
     "k": 2, 
     "efSearch": 1  
     }}}
  db.coll.aggregate([VectorSearch, VectorSearch])
  ```
+  只有当 VectorSearch 阶段不是第一个阶段时，Planner v3 才起作用。在这种情况下，MongoDB 会抛出错误，而 Planner v1 不支持 \$1VectorSearch 阶段。

  ```
  VectorSearch = { {"$vectorSearch": { 
      "queryVector": [0.2, 0.5, 0.8], 
      "path": "vectorEmbedding", 
      "similarity": "euclidean", 
      "limit": 4, 
      "numCandidates": 100} }
      
  db.coll.aggregate([$match:{}, VectorSearch])
  ```

------