

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

# 僅限索引掃描 （涵蓋的查詢）
<a name="performance-index-only-scans"></a>

**僅索引掃描** （也稱為**涵蓋查詢**) 是一種最佳化，其中 Amazon DocumentDB 完全從儲存在索引中的欄位回答查詢，而無需讀取基礎文件。由於查詢所需的值已存在於索引中，Amazon DocumentDB 可以略過擷取每個相符的文件，避免讀取完整文件的隨機 I/O 和解碼成本。在查詢計畫中，僅索引掃描會顯示為`IXONLYSCAN`階段，而不是 `IXSCAN`（索引掃描） 或 `COLLSCAN`（集合掃描）。這可減少 I/O，並可大幅降低支援查詢的查詢延遲。

當查詢只接觸單一索引中存在的一小部分欄位時，特別是當文件本身很大時，查詢是純索引掃描的理想候選項目。常見的範例是儀表板、分析彙總和查詢，從更廣泛的複合索引讀取幾個欄位。

無論是否使用僅索引掃描，查詢的結果都相同。只有查詢計畫及其執行的 I/O 數量會變更。

**注意**  
僅索引掃描支援取決於您的 Amazon DocumentDB 引擎版本：  
包含**多個**非`_id`欄位的涵蓋`find`投影需要引擎版本 8.0.2 或更新版本。在舊版中，涵蓋的`find`投影最多可包含一個非`_id` 欄位。具有兩個或多個欄位的投影會回到正常索引掃描或集合掃描。
純索引掃描是否有彙總管道，例如涵蓋的 `$group`，需要引擎版本 8.0.2 或更新版本。

## 當 Amazon DocumentDB 使用僅限索引掃描時
<a name="index-only-scans-when"></a>

當單一索引包含操作讀取的每個欄位時，Amazon DocumentDB 會考慮下列操作的僅索引掃描。

### 涵蓋的`find`投影
<a name="index-only-scans-find"></a>

當`find`查詢的投影簡單地包含一或多個頂層欄位，且每個投影欄位都存在於單一索引中時，查詢即符合資格。例如，假設 上有複合索引`{ customerId: 1, status: 1, total: 1 }`，則會涵蓋下列查詢。所有三個投影欄位都存在於索引中，`_id`並明確排除。（使用多個非`_id` 欄位覆蓋投影需要引擎版本 8.0.2 或更新版本。)

```
db.orders.createIndex({ customerId: 1, status: 1, total: 1 })

db.orders.find(
  { customerId: 42 },
  { _id: 0, customerId: 1, status: 1, total: 1 }
)
```

獲勝計劃使用 `IXONLYSCAN`階段，絕不會從儲存體擷取相符的文件：

```
{
  "stage": "IXONLYSCAN",
  "indexName": "customerId_1_status_1_total_1",
  "direction": "forward",
  "indexCond": { "$and": [ { "customerId": { "$eq": 42 } } ] }
}
```

**注意**  
在涵蓋的`find`查詢中，結果中的欄位會以**索引順序**傳回 （欄位在索引定義中出現的順序），而不是在投影中列出的順序或存放在文件中的順序。這符合涵蓋查詢的 MongoDB 行為。由集合掃描回答的查詢會改為以預存文件順序傳回欄位。

### 涵蓋的`$group`彙總
<a name="index-only-scans-group"></a>

`$group` 階段通常只會讀取幾個欄位 （群組索引鍵及其累積器的輸入），但通常會在沒有前置 的情況下執行`$match`。如果沒有涵蓋索引，Amazon DocumentDB 會讀取和解碼集合中的每個完整文件，只將這幾個欄位饋送至分組。

引擎版本 8.0.2 和更新版本中提供了彙總管道的索引限定掃描，包括涵蓋的`$group`階段。

當單一索引包含管道字首讀取的每個欄位時，Amazon DocumentDB 可以將僅索引掃描放在群組下方，並直接從索引讀取這些欄位。考慮將訂單依狀態分組的管道，並加總其總計，並在 上有複合索引`{ status: 1, total: 1 }`：

```
db.orders.createIndex({ status: 1, total: 1 })

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

管道只會讀取 `status`和 `total`，兩者都位於索引中，因此會從 饋送群組，`IXONLYSCAN`而不是集合掃描：

```
// Without a covering index
$group  <-  COLLSCAN     (reads and decodes every full document)

// With a covering index on { status, total }
$group  <-  IXONLYSCAN over { status, total }   (reads only the referenced fields)
```

在`$group`支援 `$limit`之前領導 `$skip`、、 `$match` `$sort`或 。不過，這些階段參考的每個欄位 （例如`$match`篩選欄位或`$sort`索引鍵） 也必須存在於相同的索引中，才能涵蓋管道。如果索引中缺少任何參考欄位，Amazon DocumentDB 會回到集合或索引掃描。

**注意**  
與`find`投影不同， `$group`不會隱含包含文件 `_id`。`_id` 中的 `$group`是群組索引鍵，而不是文件識別符，因此索引不需要包含文件`_id`來涵蓋管道。

## 涵蓋查詢的需求
<a name="index-only-scans-requirements"></a>

若要讓 Amazon DocumentDB 使用僅限索引掃描，必須保留下列所有項目：
+ **單一索引包含查詢讀取的每個欄位。**這包括 的投影欄位`find`，以及群組索引鍵、累積器輸入，以及涵蓋`$group`管道的任何篩選條件或排序欄位。如果索引中遺失一個欄位，則無法涵蓋查詢。
+ **投影包含最上層欄位 **（適用於 `find`)。排除投影、運算欄位和投影運算子，例如 `$slice`和 `$elemMatch` 不符合資格。
+ **`_id` 欄位會計入 **（適用於 `find`)。因為 預設`_id`包含 ，所以常見的複合索引 `{ a: 1, b: 1 }`*不包含* `find({}, { a: 1, b: 1 })`：隱含 `_id` 不在索引中。從投影中排除 `_id` (`{ _id: 0, a: 1, b: 1 }`) 或`_id`新增至索引。
+ **索引完全滿足篩選條件。**如果 Amazon DocumentDB 無法將部分查詢述詞轉換為索引繫結，則會將該部分保留為剩餘篩選條件、讀取文件以評估它，而且不會將掃描轉換為僅索引掃描。`$mod`、`$ne`、 `$nin`和 等運算子會`$exists`保留剩餘的篩選條件。
+ **沒有投影欄位是多重索引鍵 （陣列） 資料欄。**請參閱 [限制](#index-only-scans-restrictions)。

## 限制
<a name="index-only-scans-restrictions"></a>

下列案例無法使用僅索引掃描，並回到正常的索引掃描或集合掃描。這是預期的行為，絕不會影響結果的正確性。
+ **多重索引鍵 （陣列） 欄位。**如果欄位曾在任何文件中保留陣列值，則其索引欄為多索引鍵。多索引鍵索引會為每個陣列元素存放一個項目，因此無法從索引重建原始陣列。不會涵蓋讀取此類欄位的任何查詢。
+ **虛線或巢狀路徑。**巢狀路徑 上的投影或欄位參考`"address.city"`不符合資格，即使索引包含該路徑。
+ **排除、計算或運算子投影。**`{ b: 0 }`、 `{ total: { $add: ["$price", "$tax"] } }`或 等投影`{ a: { $slice: 5 } }`需要完整文件，且不涵蓋在內。
+ **彙總中的完整文件參考。**`$group` 參考整個文件 （例如 `{ $push: "$$ROOT" }`) 的 無法涵蓋，因為沒有任何索引可以重建整個文件。
+ **在 之前重塑階段`$group`。**重塑文件 （例如 `$project`、`$unwind`、 `$addFields`或 `$lookup`) 的階段，在管道`$group`不符合涵蓋資格之前出現。
+ **字串述詞上的定序不相符。**如果查詢的定序與索引的定序不同，則索引無法提供字串述詞，並留下剩餘篩選條件，強制文件擷取。數值和類型型述詞不受影響。

## 確認僅限索引掃描
<a name="index-only-scans-confirming"></a>

使用`explain("executionStats")`輸出來確認查詢是由僅索引掃描提供，且不會接觸文件。尋找兩件事：
+ 獲勝計劃使用 `IXONLYSCAN`階段。
+ 該階段`docsExamined`的值為 `0`（且`totalDocsExamined`為 `0`)，這表示查詢完全從索引中回答，而不讀取任何文件。

```
db.orders.find(
  { customerId: 42 },
  { _id: 0, customerId: 1, status: 1, total: 1 }
).explain("executionStats").executionStats
```

```
{
    "executionSuccess": true,
    "nReturned": "2",
    "executionTimeMillis": "0.714",
    "totalDocsExamined": "0",
    "executionStages": {
        "stage": "IXONLYSCAN",
        "nReturned": "2",
        "indexName": "customerId_1_status_1_total_1",
        "direction": "forward",
        "docsExamined": "0"
    }
}
```

**注意**  
`IXONLYSCAN` 階段上的非零`docsExamined`值表示索引包含資料，但 Amazon DocumentDB 仍會檢查儲存體，以確認每個文件版本都可見。當集合最近有已淘汰的文件版本垃圾回收尚未回收的寫入時，可能會發生這種情況。垃圾回收處理這些文件後， 會`docsExamined`捨棄至 `0`。此時，查詢會實現涵蓋掃描的完整優點。如需垃圾回收的詳細資訊，請參閱 [Amazon DocumentDB 中的垃圾回收](garbage-collection.md)。如需關於 `docsExamined` 指標的詳細資訊，請參閱[查詢計畫分析](performance-query-plan-analysis.md)。

## 最佳實務
<a name="index-only-scans-best-practices"></a>
+ 設計複合索引，其中包含您最常查詢專案或群組的欄位，因此可以涵蓋這些查詢。
+ `_id` 從`find`投影中排除 (`{ _id: 0, ... }`)，除非 `_id`是覆蓋索引的一部分。
+ 當您想要涵蓋查詢時，請避免索引陣列 （多索引鍵） 欄位，因為多索引鍵資料欄不符合僅索引路徑的資格。
+ 允許垃圾收集與您的寫入工作負載保持同步，讓涵蓋的掃描略過文件存取並`docsExamined`保持在 `0`。如需詳細資訊，請參閱[Amazon DocumentDB 中的垃圾回收](garbage-collection.md)。