

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 計劃快取篩選條件
<a name="plan-cache-filter"></a>

計劃快取篩選條件也稱為索引篩選條件，會限制允許查詢規劃器考慮特定查詢形狀的索引集。當查詢符合具有篩選條件的形狀時，規劃器只會從該篩選條件中名為 的索引中選擇計劃，而不是評估集合上的每個索引。

查詢形狀是查詢述詞、排序規格和集合命名空間的組合，並將述詞值標準化。兩個僅與其值不同的查詢共用一個形狀，因此單一篩選條件會涵蓋所有形狀。在 的輸出中`planCacheListFilters`，標準化值會顯示為 `"@"`。

計劃快取篩選條件可讓您鎖定計劃，以避免因為資料分佈或索引變更而選擇較慢的索引。篩選條件具有下列屬性：
+ **不需要變更應用程式。**篩選條件是使用資料庫命令設定並套用到伺服器上，因此您可以緩解迴歸，而無需部署程式碼。這是 的主要差異`hint`，必須在每個呼叫站點新增。
+ **範圍是一個查詢形狀。**形狀是由集合、述詞和排序所定義，而非完整查詢，因此篩選條件只會限制符合該形狀的查詢。相同集合上的其他查詢會繼續正常規劃。
+ **變更很耐久。**篩選條件會在執行個體重新啟動和引擎修補之間持續存在。捨棄集合會移除其篩選條件。
+ **變更是可逆的。**清除篩選條件會將形狀傳回一般成本型規劃，因此篩選條件是在調查根本原因時穩定工作負載的低風險方法。

**Topics**
+ [支援的命令](#plan-cache-filter-support)
+ [支援的查詢形狀](#plan-cache-filter-shapes)
+ [設定、列出和清除篩選條件](#plan-cache-filter-api)
+ [確認已套用篩選條件](#plan-cache-filter-explain)
+ [範例](#plan-cache-filter-examples)
+ [具有提示和索引變更的行為](#plan-cache-filter-behavior)

## 支援的命令
<a name="plan-cache-filter-support"></a>

計劃快取篩選條件需要規劃器 2.0 版或更新版本。篩選條件可套用到的命令取決於規劃器版本和 Amazon DocumentDB 次要版本，如下表所示。


**計劃快取篩選條件的命令支援**  

| 命令 | 最低規劃器版本 | 最低次要版本 | 
| --- | --- | --- | 
| `find` | 2.0 | 5.0.0、8.0.0 | 
| `count` | 2.0 | 5.0.0、8.0.0 | 
| `update` | 2.0 | 5.0.2、8.0.2 | 
| `delete` | 2.0 | 5.0.2、8.0.2 | 
| `findAndModify` | 2.0 | 5.0.2、8.0.2 | 
| `distinct` | 3.0 | 8.0.0 | 
| `aggregate` | 3.0 | 8.0.2 | 

**注意**  
規劃器 3.0 版僅適用於 Amazon DocumentDB 8.0。由於 `distinct`和 `aggregate`命令需要規劃器 3.0 版，因此這兩個命令的計劃快取篩選條件只能在 Amazon DocumentDB 8.0 中使用。在支援規劃器 2.0 版的 Amazon DocumentDB 5.0 中，篩選條件適用於 `find`、`count`、`update`、 `delete`和 `findAndModify`命令。

對於 `aggregate`命令，形狀是從管道的前面取得：領導`$match`提供篩選條件，並在提供排序`$sort`後立即取得 。 `$skip`和 `$limit` 不會影響形狀，而且 不會執行超出該點的階段。

Amazon DocumentDB 會先最佳化管道再進行規劃，並將計劃快取篩選條件與最佳化管道進行比對。因此，規劃器看到的篩選條件和排序可能會與您撰寫的階段不同。例如，管道前面的兩個相鄰`$match`階段會合併為單一`$and`述詞：

```
db.orders.aggregate([
  { $match: { status: "SHIPPED" } },
  { $match: { region: "us-east-1" } },
  { $group: { _id: "$customerId", total: { $sum: "$amount" } } }
])
```

規劃器在 `$match`上看到一個`{$and: [{status: ...}, {region: ...}]}`，因此必須在該組合述詞上設定篩選條件。

```
db.runCommand({planCacheSetFilter: "orders",
query: { $and: [ { status: "SHIPPED" }, { region: "us-east-1" } ] },
indexes: [ "status_1_region_1" ]})
```

在 `$lookup`或 `$graphLookup`階段的外部集合上設定的篩選條件會驅動用來掃描該外部集合的索引。

## 支援的查詢形狀
<a name="plan-cache-filter-shapes"></a>

從 Amazon DocumentDB 5.0.2 和 8.0.2 開始，下列運算子可能會出現在具有計劃快取篩選條件的查詢形狀中：
+ `$text`。 搜尋字串是標準化的，因此只會在搜尋時以相同形狀顯示不同的查詢。
+ `$near` 與 `$nearSphere`。兩個運算子都會標準化為相同的形狀。座標 `$minDistance`和 `$maxDistance`不是形狀的一部分。
+ `$geoWithin` 與 `$geoIntersects`。GeoJSON 幾何類型是形狀的一部分，因此`Polygon`查詢和`MultiPolygon`查詢是不同的形狀。座標不是形狀的一部分。
+ `$regex`，當直接用於欄位時。模式和選項會標準化，因此相同欄位上的所有規則表達式都會共用一個形狀。

針對使用 `$jsonSchema`、 或 的查詢形狀`$expr`，設定篩選條件失敗，錯誤碼為 303`$sampleRate`。下列形狀也會失敗。不使用篩選條件來規劃使用其中任何一個的查詢：
+ 巢`$regex`狀於 `$in`、 `$nin`或 內`$all`。混合規則表達式與常值的陣列無法針對索引進行評估，因此永遠無法套用該形狀的篩選條件。
+ 的排序規格`{$natural: 1}`。`$natural` 排序會請求集合掃描，這與將規劃器限制為 索引不相容。

## 設定、列出和清除篩選條件
<a name="plan-cache-filter-api"></a>

若要設定計劃快取篩選條件，請使用 `planCacheSetFilter`命令。`query` 和 `sort` 欄位一起指定查詢形狀，並`indexes`列出允許規劃器考慮該形狀的索引名稱。

```
db.runCommand({
planCacheSetFilter: <collection>,
query: <query>,
sort: <sort>, // optional
indexes: [ <index1>, <index2>, ...],
comment: <any> // optional
})
```

例如，下列命令會將規劃器限制為`{a: {$eq: "@"}, b: {$eq: "@"}}`無排序形狀的`a_1`索引：

```
db.runCommand({planCacheSetFilter: "foo",
query: { a: 1, b: 1 },
sort: {},
indexes: [ "a_1" ]})
```

為已有的形狀設定篩選條件會取代現有的篩選條件。執行以下兩個命令後，形狀上的篩選條件`{a: {$eq: "@"}, b: {$eq: "@"}}`為 `["b_1"]`：

```
db.runCommand({planCacheSetFilter: "foo",
query: { a: 1, b: 1 },
sort: {},
indexes: [ "a_1" ]})

db.runCommand({planCacheSetFilter: "foo",
query: { a: 6, b: 10 },
sort: {},
indexes: [ "b_1" ]})
```

若要列出集合上的每個篩選條件，請使用 `planCacheListFilters`命令：

```
db.runCommand({planCacheListFilters: <collection>})
```

輸出會顯示每個儲存的形狀及其標準化值和允許的索引清單：

```
{
"filters" : [
{
"query" : { "a" : { "$eq" : "@" } },
"sort" : { },
"indexes" : [ "a_1" ]
},
{
"query" : { "a" : { "$gt" : "@" } },
"sort" : { "a" : 1 },
"indexes" : [ "a_1_b_1" ]
}
],
"ok" : 1
}
```

運算子會保留，只有 值會取代為 `"@"`。這類隱含相等性`{a: 1}`會以其明確形式列出，`{"a": {"$eq": "@"}}`而`$in`陣列的元素會全部取代為 `{"a": {"$in": "@"}}`。沒有排序的篩選條件集會列出空白`sort`文件。

若要移除篩選條件，請使用 `planCacheClearFilters`命令。

```
db.runCommand({
planCacheClearFilters: <collection>,
query: <query pattern>, // optional
sort: <sort specification>, // optional
comment: <any> // optional
})
```

若要清除集合上的每個篩選條件，請同時省略 `query`和 `sort`：

```
db.runCommand({planCacheClearFilters: "foo"})
```

同時提供 `query`和 只會`sort`清除具有該確切排序的篩選條件。中的值`query`會經過標準化，因此任何代表性值都可以運作。若要只清除未設定排序的篩選條件，請傳遞空白`sort`文件：

```
db.runCommand({planCacheClearFilters: "foo", query: {a: 1}, sort: {a: 1}})

db.runCommand({planCacheClearFilters: "foo", query: {a: 1}, sort: {}})
```

## 確認已套用篩選條件
<a name="plan-cache-filter-explain"></a>

`explain` 輸出包含兩個報告計劃快取篩選條件狀態的欄位：
+ `indexFilterSet` 是當查詢形狀的集合上存在篩選條件`true`時。
+ `indexFilterApplied` `true`只有在使用篩選條件清單中的索引規劃查詢時， 才為 。

從 Amazon DocumentDB 5.0.2 和 8.0.2 開始，每個支援計劃快取篩選條件的命令都會報告這些欄位，並在這些命令的分析器輸出中報告這些欄位。在較早的次要版本中，僅針對 `find`命令報告它們。如需讀取解釋輸出的詳細資訊，請參閱 [查詢計畫分析](performance-query-plan-analysis.md)。

篩選條件可以比對查詢形狀，而無需套用。如果篩選條件清單中的任何索引都無法為查詢提供服務，規劃器會重新規劃沒有篩選條件，並選擇成本索引。在這種情況下， `indexFilterSet` 是 `true`， `indexFilterApplied`是 `false`。當具名索引未涵蓋查詢的欄位、具名索引不存在，或`$regex`形狀無法產生索引邊界，例如無錨定或不區分大小寫的模式時，就會發生這種情況。

## 範例
<a name="plan-cache-filter-examples"></a>

下列範例使用這些索引的`orders`集合，以及`$lookup`範例的`customers`集合：

```
db.orders.createIndex({ status: 1 })                         // status_1
db.orders.createIndex({ status: 1, orderDate: 1 })           // status_1_orderDate_1
db.orders.createIndex({ customerId: 1 })                     // customerId_1
db.customers.createIndex({ customerId: 1 })                  // customerId_1
```

### 範例：將`find`查詢鎖定到複合索引
<a name="plan-cache-filter-example-find"></a>

考慮在 上篩選`status`和排序的查詢`orderDate`：

```
db.orders.find({ status: "SHIPPED" }).sort({ orderDate: 1 })
```

複合索引同時`status_1_orderDate_1`符合述詞和排序，因此不需要個別排序。如果規劃器改為選擇 `status_1`，則查詢必須排序其結果，這會新增`SORT`階段，並隨著相符訂單的數量增加而變得更昂貴。若要將規劃器限制為此形狀的複合索引：

```
db.runCommand({planCacheSetFilter: "orders",
query: { status: "SHIPPED" },
sort: { orderDate: 1 },
indexes: [ "status_1_orderDate_1" ]})
```

由於值正規化為形狀外，因此這個篩選條件也會`status`以相同排序涵蓋 `{ status: "PENDING" }`、 `{ status: "CANCELLED" }`和 的所有其他值。它不涵蓋具有不同排序或無排序的相同述詞，這些是不同的形狀。確認篩選條件已與 生效`explain`：

```
db.orders.find({ status: "SHIPPED" }).sort({ orderDate: 1 }).explain()
```

輸出會報告 `indexFilterSet: true`和 `indexFilterApplied: true`，以及`IXSCAN`階段名稱 `status_1_orderDate_1`。

### 範例：將 鎖定`update`到選擇性索引
<a name="plan-cache-filter-example-update"></a>

更新必須找到要修改的文件，才能寫入它們，而該查詢會以讀取的相同方式使用索引。當述詞可由多個索引提供時，規劃器選擇的索引會決定更新檢查的文件數量。

```
db.orders.updateMany(
  { customerId: 4815, status: "PENDING" },
  { $set: { status: "CANCELLED" } }
)
```

`customerId_1` 和 `status_1`都可以提供此述詞。若要鎖定 的更新`customerId_1`：

```
db.runCommand({planCacheSetFilter: "orders",
query: { customerId: 4815, status: "PENDING" },
indexes: [ "customerId_1" ]})
```

寫入命令的篩選條件需要 Amazon DocumentDB 5.0.2 或 8.0.2 和規劃器 2.0 版或更新版本。使用 `explain`更新的 進行驗證：

```
db.runCommand({explain: {update: "orders",
updates: [{ q: { customerId: 4815, status: "PENDING" },
             u: { $set: { status: "CANCELLED" } },
             multi: true }]}})
```

獲勝計劃是 `IXSCAN`上 的`UPDATE`階段`customerId_1`。相同的篩選條件適用於使用此查詢形狀的 `delete`和 `findAndModify`命令，因為形狀不包含寫入類型。

### 範例：鎖定`aggregate`管道和`$lookup`外部集合
<a name="plan-cache-filter-example-aggregate"></a>

對於彙總，會從領導`$match`階段取得形狀，並在之後`$sort`立即取得 。超過 的階段，例如 `$group`或 `$project`，不屬於形狀的一部分。

```
db.orders.aggregate([
  { $match: { status: "SHIPPED" } },
  { $group: { _id: "$customerId", total: { $sum: "$amount" } } }
])
```

`$match` 述詞上的篩選條件集會驅動用於讀取 的索引`orders`：

```
db.runCommand({planCacheSetFilter: "orders",
query: { status: "SHIPPED" },
indexes: [ "status_1" ]})
```

篩選條件也適用於 `$lookup`或 `$graphLookup`階段加入的集合。篩選條件是在外部集合上設定，而不是在管道執行的集合上設定。在下列管道中， `orders` 是外部集合，而 `customers`是外部集合：

```
db.orders.aggregate([
  { $lookup: { from: "customers",
               localField: "customerId",
               foreignField: "customerId",
               as: "customer" } }
])
```

每個外部文件的聯結會探查`customers`一次，因此選擇的索引會重複套用，其成本會乘以整個管道。若要鎖定掃描到特定索引，請在 `customers` 上設定聯結索引鍵相等形狀的篩選條件：

```
db.runCommand({planCacheSetFilter: "customers",
query: { customerId: 1 },
indexes: [ "customerId_1" ]})
```

由於值是以形狀標準化，因此`1`上述值是預留位置，任何值都會產生相同的篩選條件。套用外部收集篩選條件時，頂層 `indexFilterSet`和 `indexFilterApplied` 欄位會報告 `true`，而選取的篩選條件索引會出現在獲勝計劃的外部。上的篩選條件`aggregate`需要 Amazon DocumentDB 8.0.2 和規劃器 3.0 版。

## 具有提示和索引變更的行為
<a name="plan-cache-filter-behavior"></a>
+ 計劃快取篩選條件優先於 `hint`。Amazon DocumentDB 會先套用篩選條件，然後在篩選條件允許的索引清單中套用提示。如果提示命名篩選條件允許的索引，則會使用該索引。如果提示名稱為篩選條件不允許的索引，則會忽略提示，並且規劃器會依成本選擇允許的索引。無論您命名索引或提供其金鑰模式，這兩個提示表單的行為都相同。

  例如，如果集合`foo`具有索引 `a_1`、 `b_1`和 `a_1_b_1`，而且您在形狀上設定了索引清單 `{query: {a: {$eq: "@"}, b: {$eq: "@"}}, sort: {a: 1}}`的篩選條件`["a_1", "a_1_b_1"]`，則執行 `db.foo.find({ a: 10, b: 20 }).sort({a: 1}).hint({ a: 1 })`會使用 `a_1`，因為它在提示中命名且篩選條件允許。
+ 捨棄索引不會修改篩選條件。篩選條件會保留索引名稱。當該索引遺失時，規劃會略過該索引。如果篩選條件清單中的另一個索引可以提供查詢，則篩選條件仍然適用。只有在沒有具名索引可用時，才會`indexFilterApplied`報告 `false`。以相同名稱重新建立索引會再次符合資格。
+ 捨棄集合會移除該集合的所有篩選條件。