

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

# 性能和资源利用率故障排除
<a name="user_diagnostics"></a>

本部分提供了 Amazon DocumentDB 部署中的常见诊断问题和解决方案。提供的示例使用 *mongo Shell*，并限制在单个实例范围内。要查找实例终端节点，请参阅[了解 Amazon DocumentDB 端点](endpoints.md)。

**Topics**
+ [如何确定通过 Mongo API 对我的集合执行的插入、更新和删除操作的次数？](#user-diag-performed-operations)
+ [如何分析缓存性能？](#user-diag-cache-perf)
+ [如何查找和终止长时间运行或受阻的查询？](#user_diagnostics-query_terminating)
+ [如何查看查询计划和优化查询？](#user_diagnostics-query_plan)
+ [如何在弹性集群中查看查询计划？](#user-diagnostics-ec-query-plan)
+ [如何列出实例上所有正在运行的操作？](#user_diagnostics-list_queries)
+ [如何知道查询何时取得进展？](#user_diagnostics-query_progressing)
+ [如何确定系统突然运行缓慢的原因？](#user_diagnostics-speed_change)
+ [如何确定一个或多个集群实例上 CPU 使用率过高的原因？](#user_diagnostics-cpu_utilization)
+ [如何确定实例上打开的光标？](#user_diagnostics-open_cursors)
+ [如何确定当前的 Amazon DocumentDB 引擎版本？](#user_diagnostics-engine_version)
+ [如何分析索引使用情况并识别未使用的索引？](#user-diag-index-usage)
+ [如何识别缺失的索引？](#user_diagnostics-identify_missing_indexes)
+ [如何确定数据库集合膨胀？](#performance-collection-bloat)
+ [有用查询的摘要](#user_diagnostics-useful_queries)

## 如何确定通过 Mongo API 对我的集合执行的插入、更新和删除操作的次数？
<a name="user-diag-performed-operations"></a>

要查看对某个集合执行的插入、更新和删除操作的数量，请对该集合运行以下命令：

```
db.collection.stats()
```

此命令的输出在其 `opCounters` 字段下描述了以下内容：
+ **numDocsIns**-插入到此集合中的文档数量。这包括使用 `insert` 和 `insertMany` 命令插入的文档，以及通过更新插入的文档。
+ **numDocsUpd**-此集合中更新的文档数量。这包括使用 `update` 和 `findAndModify` 命令更新的文档。
+ **numDocsDel**-从该集合中删除的文档数量。这包括使用`deleteOne`、`deleteMany`、`remove`、和 `findAndModify` 命令删除的文档。
+ **lastReset**：上次重置这些计数器的时间。当集群或扩展 up/down 实例时 starting/stopping ，此命令提供的统计数据将被重置。

运行 `db.collection.stats()` 的输出示例如下。

```
{
    "ns" : "db.test",
    "count" : ...,
    "size" : ...,
    "avgObjSize" : ...,
    "storageSize" : ...,
    "capped" : false,
    "nindexes" : ...,
    "totalIndexSize" : ...,
    "indexSizes" : {
        "_id_" : ...,
        "x_1" : ...
    },
    "collScans" : ...,
    "idxScans" : ...,
    "opCounter" : {
        "numDocsIns" : ...,
        "numDocsUpd" : ...,
        "numDocsDel" : ...
    },
    "cacheStats" : {
        "collBlksHit" : ...,
        "collBlksRead" : ..,
        "collHitRatio" : ...,
        "idxBlksHit" : ...,
        "idxBlksRead" : ...,
        "idxHitRatio" : ...
    },
    "lastReset" : "2022-09-02 19:41:40.471473+00",
    "ok" : 1,
    "operationTime" : Timestamp(1662159707, 1)
}
```

通过 Mongo API 查看用于插入、更新和删除操作的集合专用计数器时，应使用此 stats 命令。另一种查看特定于集合的操作计数器的方法是启用 DML 审核。可以在 [使用以下方式监控亚马逊 DocumentDB CloudWatch](cloud_watch.md) 中查看在一分钟时间间隔内对所有集合执行的插入、更新和删除操作的次数。

## 如何分析缓存性能？
<a name="user-diag-cache-perf"></a>

分析缓存性能可以深入了解数据检索的效率和系统性能，并且基于从磁盘读取的数据量与从缓存中读取的数据量。我们提供有关缓存命中次数（从缓存中读取的数据）和缓存未命中（在缓存中找不到并从磁盘读取的数据）的缓存统计信息，以便深入了解缓存性能。通过对该集合运行以下命令可以找到特定集合的缓存统计信息：

```
db.collection.stats()
```

此命令输出中 `cacheStats` 字段中的值提供集合的缓存统计信息，以及在集合上创建的索引的缓存总统计信息。以下列出了这些统计数据：
+ **`collBlksHit`**：操作此集合期间从缓存中读取的块数。
+ **`collBlksRead`**：操作此集合期间从磁盘读取的块数（缓存未命中）。
+ **`collHitRatio`**：此集合的缓存命中率 (`100 * [collBlksHit / (collBlksHit + collBlksRead)]`)。
+ **`idxBlksHit`**：从缓存中读取在此集合上创建的任何索引的块数。
+ **`idxBlksRead`**：在此集合上创建的任何索引从磁盘读取的块数（缓存未命中）。
+ **`idxHitRatio`**：在此集合上创建的索引的缓存命中率 (`100 * [idxBlksHit / (idxBlksHit + idxBlksRead)]`)。
+ **`lastReset`**：上次重置这些统计数据的时间。集群或扩展 up/down 实例时 starting/stopping ，提供的统计数据会`db.collection.stats()`被重置。

也可以使用 `indexStats` 命令查看每个索引的 `idxBlksHit` 和 `idxBlksRead` 字段的细分。运行以下命令可以找到特定于索引的缓存统计信息：

```
db.collection.aggregate([{$indexStats:{}}]).pretty()
```

对于每个索引，可以在 `cacheStats` 字段下找到以下缓存统计信息：
+ **`blksHit`**：从缓存中读取此索引的数据块的数量。
+ **`blksRead`**：从磁盘中读取此索引的数据块的数量。
+ **`blksHitRatio`**：缓存命中率四舍五入到小数点后四位，计算公式为 `100 * [blksHit / (blksHit + blksRead)]`。

## 如何查找和终止长时间运行或受阻的查询？
<a name="user_diagnostics-query_terminating"></a>

用户查询可能因查询计划不够理想而运行缓慢，或者由于资源争用而受阻。

要查找因查询计划不够理想而速度缓慢的长时间运行的查询，或者由于资源争用而受阻的查询，请使用 `currentOp` 命令。可以筛选该命令以帮助缩小要终止的相关查询的列表。长时间运行的查询必须拥有关联的 `opid`，才能够终止查询。

以下查询使用 `currentOp` 命令列出受阻或运行时间超过 10 秒的所有查询。

```
db.adminCommand({
    aggregate: 1,
    pipeline: [
        {$currentOp: {}},
        {$match: 
            {$or: [
                {secs_running: {$gt: 10}},
                {WaitState: {$exists: true}}]}},
        {$project: {_id:0, opid: 1, secs_running: 1}}],
    cursor: {}
});
```

接下来，您可以缩小查询，以查找运行时间超过 10 秒的查询的 `opid` 并终止它。

**查找并终止运行时间超过 10 秒的查询**

1. 查找查询的 `opid`。

   ```
   db.adminCommand({
       aggregate: 1,
       pipeline: [
           {$currentOp: {}},
           {$match: 
               {$or: 
                   [{secs_running: {$gt: 10}},
                    {WaitState: {$exists: true}}]}}],
       cursor: {}
   });
   ```

   此操作的输出将类似于下文（JSON 格式）。

   ```
   {
       "waitedMS" : NumberLong(0),
       "cursor" : {
           "firstBatch" : [
               {
                   "opid" : 24646,
                   "secs_running" : 12 
               }
           ],
           "id" : NumberLong(0),
           "ns" : "admin.$cmd"
       },
       "ok" : 1
   }
   ```

1. 使用 `killOp` 操作终止查询。

   ```
   db.adminCommand({killOp: 1, op: 24646});
   ```

## 如何查看查询计划和优化查询？
<a name="user_diagnostics-query_plan"></a>

如果查询运行缓慢，可能是因为查询执行需要对集合进行完全扫描以选择相关的文档。有时，可通过创建合适的索引提高查询的运行速度。要检测此情形并确定要在其中创建索引的字段，请使用 `explain` 命令。

**注意**  
Amazon DocumentDB 在利用分布式、容错、自修复的存储系统的专用数据库引擎上模拟 MongoDB 3.6 API。因此，查询计划和 `explain()` 的输出在 Amazon DocumentDB 和 MongoDB 之间可能有所不同。希望控制其查询计划的客户可以使用 `$hint` 运算符强制选择首选索引。

在 `explain` 命令下运行要改进的查询，如下所示。

```
db.runCommand({explain: {<query document>}})
```

以下是操作示例。

```
db.runCommand({explain:{
    aggregate: "sample-document",
    pipeline: [{$match: {x: {$eq: 1}}}],
    cursor: {batchSize: 1}}
});
```

此操作的输出将类似于下文（JSON 格式）。

```
{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "db.test",
        "winningPlan" : {
            "stage" : "COLLSCAN"
        }
    },
    "serverInfo" : {
        "host" : "...",
        "port" : ...,
        "version" : "..."
    },
    "ok" : 1
}
```

上述输出表明，`$match` 阶段要求扫描整个集合并检查每个文档中的字段 `"x"` 是否等于 1。如果集合中有很多文档，集合扫描将非常慢，因此整体查询性能非常低。因此，`explain` 命令输出中的 `"COLLSCAN"` 的存在表明，可以通过创建合适的索引来提高查询性能。

在本例中，查询检查所有文档中的字段 `"x"` 是否等于 1。因此，在字段 `"x"` 上创建索引，可使查询避免对集合进行完全扫描，并可使用索引更快地返回相关文档。

在字段 `"x"` 上创建索引后，`explain` 输出如下所示。

```
{
    "queryPlanner" : {
         "plannerVersion" : 1,
         "namespace" : "db.test",
         "winningPlan" : {
             "stage" : "IXSCAN",
             "indexName" : "x_1",
             "direction" : "forward"
         }
    },
    "serverInfo" : {
        "host" : "...",
        "port" : ...,
        "version" : "..."
    },
    "ok" : 1
}
```

因此，在 `"x"` 字段上创建索引后，`$match` 阶段即可使用索引扫描来减少必须对其评估 `"x = 1"` 谓词的文档的数量。

对于较小的集合，如果性能增益微乎其微，Amazon DocumentDB 查询处理器可以选择不使用索引。

## 如何在弹性集群中查看查询计划？
<a name="user-diagnostics-ec-query-plan"></a>

要检查弹性集群中的查询计划，请使用 `explain` 命令。以下是针对分片集合的查找查询的 `explain` 操作示例：

```
db.runCommand(
   {
     explain: { find: "cities", filter: {"name": "Seoul"}}
   }
)
```

**注意**  
Amazon DocumentDB 在专用数据库引擎上模拟 MongoDB。因此，查询计划和 `explain()` 的输出在 Amazon DocumentDB 和 MongoDB 之间可能有所不同。您可以使用 `$hint` 运算符强制选择首选索引来控制查询计划。

此操作的输出将可能类似于下文（JSON 格式）。

```
{
  "queryPlanner" : {
    "elasticPlannerVersion" : 1,
    "winningPlan" : {
      "stage" : "SINGLE_SHARD",
      "shards" : [
        {
          "plannerVersion" : 1,
          "namespace" : "population.cities",
          "winningPlan" : {
            "stage" : "SHARD_MERGE",
            "shards" : [
              {
                "shardName" : "f2cf5cfd-fe9c-40ca-b4e5-298ca0d11111",
                "plannerVersion" : 1,
                "namespace" : "population.cities",
                "winningPlan" : {
                  "stage" : "PARTITION_MERGE",
                  "inputStages" : [
                    {
                      "stage" : "COLLSCAN",
                      "partitionCount" : 21
                    }
                  ]
                }
              },
              {
                "shardName" : "8f3f80e2-f96c-446e-8e9d-aab8c7f22222",
                "plannerVersion" : 1,
                "namespace" : "population.cities",
                "winningPlan" : {
                  "stage" : "PARTITION_MERGE",
                  "inputStages" : [
                    {
                      "stage" : "COLLSCAN",
                      "partitionCount" : 21
                    }
                  ]
                }
              },
              {
                "shardName" : "32c5a06f-1b2b-4af1-8849-d7c4a033333",
                "plannerVersion" : 1,
                "namespace" : "population.cities",
                "winningPlan" : {
                  "stage" : "PARTITION_MERGE",
                  "inputStages" : [
                    {
                      "stage" : "COLLSCAN",
                      "partitionCount" : 22
                    }
                  ]
                }
              }
            ]
          },
          "shardName" : "32c5a06f-1b2b-4af1-8849-d7c4a0f3fb58"
        }
      ]
    }
  },
  "serverInfo" : {
    "host" : "example-4788267630.us-east-1.docdb-elastic.amazonaws.com:27017",
    "version" : "5.0.0"
  },
  "ok" : 1,
  "operationTime" : Timestamp(1695097923, 1)
}
```

前面的输出显示了三分片集群上 `find` 查询的查询计划。每个分片都有多个数据分区，这些分区可以有不同的输入阶段。在此示例中，在每个分片的“PARTITION\$1MERGE”阶段合并结果之前，将在所有分区上运行“COLLSCAN”（集合扫描）。然后，分片上的结果在“SHARD\$1MERGE”阶段合并在一起，再发送回客户端。

## 如何列出实例上所有正在运行的操作？
<a name="user_diagnostics-list_queries"></a>

作为用户或主用户，您经常需要列出实例上当前正在运行的所有操作，以进行诊断和故障排除。（有关管理用户的信息，请参阅[管理 Amazon DocumentDB 用户](security.managing-users.md)）。

借助 `mongo` Shell，您可以使用以下查询列出 Amazon DocumentDB 实例上正在运行的所有操作。

```
db.adminCommand({currentOp: 1, $all: 1});
```

该查询返回当前在实例上运行的所有用户查询和内部系统任务的完整列表。

此操作的输出将类似于下文（JSON 格式）。

```
{
    "inprog" : [
        {
            "desc" : "INTERNAL"
        },
        {
            "desc" : "TTLMonitor",
            "active" : false
        },
        {
            "client" : ...,
            "desc" : "Conn",
            "active" : true,
            "killPending" : false,
            "opid" : 195,
            "ns" : "admin.$cmd",
            "command" : {
                "currentOp" : 1,
                "$all" : 1
            },
            "op" : "command",
            "$db" : "admin",
            "secs_running" : 0,
            "microsecs_running" : NumberLong(68),
            "clientMetaData" : {
            "application" : {
                "name" : "MongoDB Shell"
            },
            "driver" : {
                ...
            },
            "os" : {
                ...
            }
          }
       },
       {
          "desc": "GARBAGE_COLLECTION",
          "garbageCollection": {
             "databaseName": "testdb",
             "collectionName": "testCollectionA"
          },
          "secs_running": 3,
          "microsecs_running": NumberLong(3123456)
       },
       {
          "desc": "GARBAGE_COLLECTION",
          "garbageCollection": {
             "databaseName": "testdb",
             "collectionName": "testCollectionB"
          },
          "secs_running": 4,
          "microsecs_running": NumberLong(4123456)
       }
    ],
    "ok" : 1
}
```

`"desc"` 字段的有效值如下所示：
+ **INTERNAL**：内部系统任务，如游标清理或过时用户清理任务。
+ **TTLMonitor**：生存时间 (TTL) 监视器线程。其运行状态在 `"active"` 字段中反映。
+ **GARBAGE\$1COLLECTION**：内部垃圾收集器线程。
+ **CONN**：用户查询。
+ **CURSOR**：该操作是一个空闲的光标，等待用户调用“getMore”命令以获取下一批结果。在此状态下，光标正在消耗内存，但不消耗任何计算。

上述输出还列出了在系统中运行的所有用户查询。每个用户查询都在数据库和集合的上下文中运行，而这二者的并集称为*命名空间*。每个用户查询的命名空间都可在 `"ns"` 字段中获得。

有时，您需要列出在特定命名空间中运行的所有用户查询。因此，必须在 `"ns"` 字段上过滤之前的输出。下面是一个实现要筛选的输出的示例查询。该查询列出当前在数据库 `"db"` 和集合 `"test"`（即 `"db.test"` 命名空间）中运行的所有用户查询。

```
db.adminCommand({aggregate: 1,
    pipeline: [{$currentOp: {allUsers: true, idleConnections: true}},
               {$match: {ns: {$eq: "db.test"}}}],
    cursor: {}
});
```

作为系统主用户，您可以查看所有用户的查询以及所有内部系统任务。所有其他用户只能查看其各自的查询。

如果查询和内部系统任务的总数超过默认批处理游标大小，则 `mongo` Shell 将自动生成迭代器对象 `'it'` 以查看其余结果。可继续执行 `'it'` 命令，直到查看完所有结果。

## 如何知道查询何时取得进展？
<a name="user_diagnostics-query_progressing"></a>

用户查询可能由于不够理想的查询计划而运行缓慢，或可能由于资源争用而受阻。调试此类查询是一个多步骤过程，可能需要多次执行相同的步骤。

调试的第一步是列出长时间运行或受阻的所有查询。以下查询列出了运行时间超过 10 秒或正在等待资源的所有用户查询。

```
db.adminCommand({aggregate: 1,
                 pipeline: [{$currentOp: {}},
                            {$match: {$or: [{secs_running: {$gt: 10}},
                                            {WaitState: {$exists: true}}]}},
                            {$project: {_id:0,
                                        opid: 1,
                                        secs_running: 1,
                                        WaitState: 1,
                                        blockedOn: 1,
                                        command: 1}}],
                 cursor: {}
                });
```

定期重复上述查询以确定查询列表更改并识别长时间运行或受阻的查询。

如果相关的查询的输出文档具有 `WaitState` 字段，则表示资源争用是查询运行缓慢或受阻的原因。资源争用可能由 I/O、内部系统任务或其他用户查询导致。

此操作的输出将类似于下文（JSON 格式）。

```
{
    "waitedMS" : NumberLong(0),
    "cursor" : {
        "firstBatch" : [
            {
                "opid" : 201,
                "command" : {
                    "aggregate" : ...
                },
                "secs_running" : 208,
                "WaitState" : "IO"
            }
        ],
        "id" : NumberLong(0),
        "ns" : "admin.$cmd"
    },
    "ok" : 1
}
```

如果不同集合中的很多查询并行运行在同一实例上，或者实例大小对于运行查询的数据集而言过小，则 I/O 可能是瓶颈所在。如果查询是只读查询，您可以通过在不同副本中分隔每个集合的查询来缓解上述情况。对于跨不同集合的并发更新，或者当实例大小对数据集而言过小时，您可以通过向上扩展实例来进行缓解。

如果资源争用是由其他用户查询引起的，则输出文档中的 `"blockedOn"` 字段将具有影响此查询的查询的 `"opid"`。利用 `"opid"`，可沿着所有查询的 `"WaitState"` 和 `"blockedOn"` 字段的链查找位于链头的查询。

如果链头的任务是一个内部任务，那么在这种情况下的唯一缓解措施将是，终止查询之后重新运行它。

下面是一个示例输出，其中的查找查询在由另一个任务拥有的集合锁上被阻止。

```
{
    "inprog" : [
        {
            "client" : "...",
            "desc" : "Conn",
            "active" : true,
            "killPending" : false,
            "opid" : 75,
            "ns" : "...",
            "command" : {
                "find" : "...",
                "filter" : {

                }
            },
            "op" : "query",
            "$db" : "test",
            "secs_running" : 9,
            "microsecs_running" : NumberLong(9449440),
            "threadId" : 24773,
            "clientMetaData" : {
                "application" : {
                   "name" : "MongoDB Shell"
                },
                "driver" : {
                    ...
                },
                "os" : {
                    ...
                }
            },
            "WaitState" : "CollectionLock",
            "blockedOn" : "INTERNAL"
        },
        {
            "desc" : "INTERNAL"
        },
        {
            "client" : "...",
            ...
            "command" : {
                "currentOp" : 1
            },
            ...
        }
    ],
    "ok" : 1
}
```

如果 `"WaitState"` 具有值 `"Latch"`、`"SystemLock"`、`"BufferLock"`、`"BackgroundActivity"` 或 `"Other"`，则资源争用的来源为内部系统任务。如果这种情况持续了很长时间，则唯一的缓解措施将是，终止查询并在之后重新运行。

## 如何确定系统突然运行缓慢的原因？
<a name="user_diagnostics-speed_change"></a>

以下是系统速度减慢的一些常见原因：
+ 并发查询之间的资源争用过多 
+ 活动并发查询的数量会随着时间的推移而增加
+ 内部系统任务，例如 `"GARBAGE_COLLECTION"`

要监控系统的长期使用情况，请定期运行以下 `"currentOp"` 查询并将结果输出到外部存储。此查询会计算系统中每个命名空间中的查询和操作数。您可以分析系统使用情况的结果以了解系统上的负载并做出适当的决策。

```
db.adminCommand({aggregate: 1,
                 pipeline: [{$currentOp: {allUsers: true, idleConnections: true}},
                            {$group: {_id: {desc: "$desc", ns: "$ns", WaitState: "$WaitState"}, count: {$sum: 1}}}],
                 cursor: {}
                });
```

此查询将返回在每个命名空间中运行的所有查询和所有内部系统任务的聚合，以及每个命名空间的等待状态（如果有）的数量。

此操作的输出将类似于下文（JSON 格式）。

```
{
    "waitedMS" : NumberLong(0),
    "cursor" : {
        "firstBatch" : [
            {
                "_id" : {
                    "desc" : "Conn",
                    "ns" : "db.test",
                    "WaitState" : "CollectionLock"
                },
               "count" : 2
            },
            {
                "_id" : {
                    "desc" : "Conn",
                    "ns" : "admin.$cmd"
                },
                "count" : 1
            },
            {
                "_id" : {
                    "desc" : "TTLMonitor"
                },
                "count" : 1
            }
        ],
        "id" : NumberLong(0),
        "ns" : "admin.$cmd"
    },
    "ok" : 1
}
```

在上述输出中，命名空间 `"db.test"` 中有两个用户查询在集合锁上被阻止，命名空间 `"admin.$cmd"` 中有一个查询，另外还有一个内部 `"TTLMonitor"` 任务。

如果输出表明有许多查询处于受阻等待状态，请参阅[如何查找和终止长时间运行或受阻的查询？](#user_diagnostics-query_terminating)

## 如何确定一个或多个集群实例上 CPU 使用率过高的原因？
<a name="user_diagnostics-cpu_utilization"></a>

以下各节可以帮助您确定实例 CPU 使用率过高的原因。根据工作负载，您的结果可能会有所不同。
+ 要确定实例突然运行缓慢的原因，请参阅[如何确定系统突然运行缓慢的原因？](#user_diagnostics-speed_change) 
+ 要确定并终止特定实例上长时间运行的查询，请参阅[如何查找和终止长时间运行或受阻的查询？](#user_diagnostics-query_terminating) 
+ 要了解查询是否取得进展，请参阅[如何知道查询何时取得进展？](#user_diagnostics-query_progressing) 
+ 要确定查询长时间运行的原因，请参阅[如何查看查询计划和优化查询？](#user_diagnostics-query_plan)
+ 要跟踪一段时间内长时间运行的查询，请参阅 [分析 Amazon DocumentDB 操作](profiling.md)。

根据实例 CPU 使用率高的原因，执行以下一项或多项操作可能会有所帮助。
+ 如果主实例的 CPU 利用率较高，但副本实例没有，请考虑通过客户端读取首选项设置（例如 `secondaryPreferred`）在副本之间分配读取流量。有关更多信息，请参阅 [作为副本集连接到 Amazon DocumentDB](connect-to-replica-set.md)。

  使用副本进行读取可以让主实例处理更多的写入流量，从而更好地利用集群的资源。从副本中读取的数据最终是一致的。
+ 如果写入工作负载导致高 CPU 使用率，则将集群实例的大小更改为更大的实例类型会增加可用于为该工作负载提供服务的 CPU 内核数量。有关更多信息，请参阅[实例](what-is.md#what-is-db-instances)和[实例类规格](db-instance-classes.md#db-instance-class-specs)。
+ 如果所有集群实例都表现出较高的 CPU 利用率，并且工作负载使用副本进行读取，则向集群添加更多副本会增加可用于读取流量的资源。有关更多信息，请参阅 [向集群添加 Amazon DocumentDB 实例](db-instance-add.md)。

## 如何确定实例上打开的光标？
<a name="user_diagnostics-open_cursors"></a>

连接到 Amazon DocumentDB 实例后，您可以使用命令 `db.runCommand("listCursors")` 列出该实例上打开的光标。在给定的 Amazon DocumentDB 实例上，在任何给定时间最多只能打开 4,560 个活动光标，具体取决于实例类型。通常建议关闭不再使用的游标，因为游标占用实例上的资源并具有上限。有关具体限制，请参阅 [Amazon DocumentDB 配额和限制](limits.md)。

```
db.runCommand("listCursors") 
```

## 如何确定当前的 Amazon DocumentDB 引擎版本？
<a name="user_diagnostics-engine_version"></a>

要确定当前的 Amazon DocumentDB 引擎版本，请运行以下命令。

```
db.runCommand({getEngineVersion: 1})
```

此操作的输出将类似于下文（JSON 格式）。

```
{ "engineVersion" : "2.x.x", "ok" : 1 }
```

**注意**  
亚马逊 DocumentDB 3.6 的引擎版本为 1.x.x，亚马逊 DocumentDB 4.0 的引擎版本为 2.x.x，亚马逊 DocumentDB 5.0 的引擎版本为 3.x.x，亚马逊 DocumentDB 8.0 的引擎版本为 4.x.x。

## 如何分析索引使用情况并识别未使用的索引？
<a name="user-diag-index-usage"></a>

要识别给定集合的索引，请运行以下命令：

```
db.collection.getIndexes()
```

要分析在对集合执行操作期间使用了多少索引，可以使用 `collStats` 和 `indexStats` 命令。要查看使用索引（索引扫描）执行的扫描总数与不使用索引执行的扫描数（集合扫描）的对比，请运行以下命令：

```
db.collection.stats()
```

此命令的输出包括以下值：
+ **`idxScans`**：使用索引对该集合执行的扫描次数。
+ **`collScans`**：不使用索引对此集合执行的扫描次数。这些扫描将涉及逐一查看馆藏中的文档。
+ **`lastReset`**：上次重置这些计数器的时间。当集群或扩展 up/down 实例时 starting/stopping ，此命令提供的统计数据将被重置。

在以下命令的输出中可以找到每个索引的使用量明细。为了提高性能和降低成本，最佳做法是定期识别和删除未使用的索引，因为这样可以省去不必要的计算、存储，并 I/Os 用于维护索引。

```
db.collection.aggregate([{$indexStats:{}}]).pretty()
```

此命令的输出给出了在集合上创建的每个索引的以下值：
+ **`ops`**：使用索引的操作数。如果您的工作负载已经运行了足够长的时间，并且您确信自己的工作负载处于稳定状态，则 `ops` 值为零表示根本没有使用索引。
+ **`numDocsRead`**：使用此索引进行操作期间读取的文档数。
+ **`since`**：自 Amazon DocumentDB 开始收集索引使用统计数据以来的时间，该值通常是自上次数据库重启或维护操作以来的值。
+ **`size`**：索引的大小以字节为单位。

下面的示例是从以上命令中的样本输出。

```
{
    "name" : "_id_",
    "key" : {
        "_id" : 1
    },
    "host" : "example-host.com:12345",
    "size" : NumberLong(...),
    "accesses" : {
        "ops" : NumberLong(...),
        "docsRead" : NumberLong(...),
        "since" : ISODate("...")
    },
    "cacheStats" : {
        "blksRead" : NumberLong(...),
        "blksHit" : NumberLong(...),
        "hitRatio" : ...
    }
}
{
    "name" : "x_1",
    "key" : {
        "x" : 1
    },
    "host" : "example-host.com:12345",
    "size" : NumberLong(...),
    "accesses" : {
        "ops" : NumberLong(...),
        "docsRead" : NumberLong(...),
        "since" : ISODate("...")
    },
    "cacheStats" : {
        "blksRead" : NumberLong(...),
        "blksHit" : NumberLong(...),
        "hitRatio" : ...
    }
}
```

要确定集合的整体索引大小，请运行以下命令：

```
db.collection.stats()
```

要删除未使用的索引，请运行以下命令：

```
db.collection.dropIndex("indexName")
```

## 如何识别缺失的索引？
<a name="user_diagnostics-identify_missing_indexes"></a>

您可以使用 [Amazon DocumentDB 分析器来记录慢速查询](https://docs.aws.amazon.com//documentdb/latest/developerguide/profiling.html)。在慢速查询日志中反复出现的查询可能表示需要额外的索引才能提高该查询的性能。

您可以通过寻找具有一个或多个阶段至少执行一个 `COLLSCAN` 阶段的长时间运行的查询来发现有用索引的机会，这意味着查询阶段必须读取集合中的每个文档才能对查询提供响应。

以下示例显示了对在大型集合上运行的出租车乘车集合的查询。

```
db.rides.count({"fare.totalAmount":{$gt:10.0}}))
```

为了执行此示例，查询必须执行集合扫描（即读取集合中的每个文档），因为 `fare.totalAmount` 字段上没有索引。此查询的 Amazon DocumentDB 分析器输出如下所示：

```
{
    ...
    "cursorExhausted": true,
    "nreturned": 0, 
    "responseLength": 0,
    "protocol": "op_query",
    "millis": 300679,
    "planSummary": "COLLSCAN",
    "execStats": {
        "stage": "COLLSCAN",
        "nReturned": "0",
        "executionTimeMillisEstimate": "300678.042"
    },
    "client": "172.31.5.63:53878",
    "appName": "MongoDB Shell",
    "user": "example"
}
```

为了加快本示例中的查询速度，您需要在 `fare.totalAmount` 上创建索引，如下所示。

```
db.rides.createIndex( {"fare.totalAmount": 1}, {background: true} )
```

**注意**  
在前台创建的索引（即如果在创建索引时未提供 `{background:true}` 选项）采用独占写入锁，这可以防止应用程序在索引构建完成之前将数据写入集合。在生产集群上创建索引时，请注意这种潜在影响。创建索引时，我们建议设置 `{background:true}`。

通常，您希望在具有高基数的字段（例如，大量唯一值）上创建索引。在基数较低的字段上创建索引可能会导致不使用的索引过大。Amazon DocumentDB 查询优化器在创建查询计划时会考虑集合的总体大小和索引的选择性。有时候，即使存在索引，您也会看到查询处理器选择一个 `COLLSCAN`。当查询处理器估计使用索引不会比扫描整个集合更具性能优势时，就会发生这种情况。如果要强制查询处理器使用特定的索引，则可以使用如下所示的 `hint()` 运算符。

```
db.collection.find().hint("indexName")
```

## 如何确定数据库集合膨胀？
<a name="performance-collection-bloat"></a>

当集合的大小因失效或过时的文档累积或数据库页面内的碎片累积而变大时，就会出现集合膨胀。报告的百分比表示未来文档可以使用的文档空间量。此膨胀会同时消耗缓冲区缓存和存储空间中的空间。要消除膨胀，必须在维护时段内通过 dump/restore 或使用迁移环回和切换来重新加载集合。

**Example 示例**  
运行以下命令以确定集合未使用的存储空间：  

```
db.runCommand({collStats:'coll'})
```
结果类似如下：  

```
{
        "ns" : "test.coll",
        "count" : 7500,
        "size" : 23250,
        "avgObjSize" : 31,
        "storageSize" : 106496,
        "unusedStorageSize" : {
                "unusedBytes" : 16384,
                "unusedPercent" : 25.12
        },
        "compression" : {
                "enable" : false
        },
        "capped" : false,
        "nindexes" : 1,
        "totalIndexSize" : 57344,
        "indexSizes" : {
                "_id_" : 57344
        },
        "collScans" : 4,
        "idxScans" : 10000,
        "opCounter" : {
                "numDocsIns" : 1000,
                "numDocsUpd" : 0,
                "numDocsDel" : 250
        },
        "cacheStats" : {
                "collBlksHit" : 3570,
                "collBlksRead" : 8,
                "collHitRatio" : 99.7765,
                "idxBlksHit" : 12293,
                "idxBlksRead" : 6,
                "idxHitRatio" : 99.9513
        },
        "lastReset" : "2024-12-18 00:30:21.552019+00",
        "ok" : 1,
        "operationTime" : Timestamp(1734632375, 1)
}
```

## 有用查询的摘要
<a name="user_diagnostics-useful_queries"></a>

以下查询可用于监控 Amazon DocumentDB 中的性能和资源利用率。
+ 使用以下命令查看有关特定集合的统计信息，包括操作计数器、缓存统计信息、访问统计信息和大小统计信息：

  ```
  db.collection.stats()
  ```
+ 使用以下命令查看有关在集合上创建的每个索引的统计信息，包括索引的大小、索引特定的缓存统计信息和索引使用情况统计信息：

  ```
  db.collection.aggregate([{$indexStats:{}}]).pretty()
  ```
+ 使用以下查询列出所有活动。

  ```
  db.adminCommand({currentOp: 1, $all: 1});
  ```
+ 以下代码列出了所有长时间运行或已阻止的查询。

  ```
  db.adminCommand({aggregate: 1,
                   pipeline: [{$currentOp: {}},
                              {$match: {$or: [{secs_running: {$gt: 10}},
                                              {WaitState: {$exists: true}}]}},
                              {$project: {_id:0,
                                          opid: 1,
                                          secs_running: 1,
                                          WaitState: 1,
                                          blockedOn: 1,
                                          command: 1}}],
                   cursor: {}
                  });
  ```
+ 以下代码终止查询。

  ```
  db.adminCommand({killOp: 1, op: <opid of running or blocked query>});
  ```
+ 使用以下代码获取系统状态的汇总视图。

  ```
  db.adminCommand({aggregate: 1,
                   pipeline: [{$currentOp: {allUsers: true, idleConnections: true}},
                              {$group: {_id: {desc: "$desc", ns: "$ns", WaitState: "$WaitState"}, count: {$sum: 1}}}],
                   cursor: {}
                  });
  ```