
# 慢请求定位方法
#### 操作场景
在相同的业务场景中，架构设计以及库、集合、索引等的设计都会对查询性能产生影响。良好的设计能够提升查询性能，而不当的设计则会导致大量慢查询（执行时间过长的语句），这些慢查询会消耗大量的系统性能。本文主要介绍导致慢查询的原因及相应的解决方案。
#### 排查思路
DDS支持在控制台上[查看慢日志信息](https://support.huaweicloud.com/usermanual-dds/zh-cn_topic_slow_query_log.html)，针对慢日志中过长的操作需要从执行最慢的操作入手，逐个进行优化。
- 对于操作执行时长超过1s时，对应的操作可能会有问题，需要视具体情况分析。
- 对于操作执行时长超过10s时，则需要优化对应的操作。
  ![](https://support.huaweicloud.com/usermanual-dds/public_sys-resources/note_3.0-zh-cn.png)
  若存在某个聚合操作，因其比较慢，此时操作执行时长超过10s的情况属于正常现象。
  
 
#### 操作步骤
#### 分析方法
1. 连接数据库。 
   - 集群实例，请参见[连接集群实例](https://support.huaweicloud.com/usermanual-dds/dds_03_0308.html)。
   
   - 副本集实例，请参见[连接副本集实例](https://support.huaweicloud.com/usermanual-dds/dds_03_0326.html)。
   
   - 单节点实例，请参见[连接单节点实例](https://support.huaweicloud.com/usermanual-dds/dds_03_0344.html)。
   
   
   
   
2. 针对慢查询可以通过如下命令检查其执行计划。 
   **explain()**
   例如：
   ```
   db.test.find({"data_id" : "ae4b5769-896f-465c-9fbd-3fd2f3357637"}).explain();
   db.test.find({"data_id" : "775f57c2-b63e-45d7-b581-3822dba231b4"}).explain("executionStats");
   ```
   对于查询而言，因为覆盖查询不需要读取文档，而是直接从索引中返回结果，这样的查询非常高效，所以**尽可能使用索引覆盖查询**。如果explain()的输出显示indexOnly字段为真，则说明这个查询就被一个索引覆盖。
   
   
3. 执行计划解析。 
   1. 查看执行时间。 executionStats.executionStages.executionTimeMillisEstimate和executionStats.executionStages.inputStage. executionTimeMillisEstimate时间越短越好。
      表1参数说明 
      | 参数名称                                                                   | 描述              |
      |:---|:---|
      | executionStats.executionTimeMillis                                     | 执行计划选择和执行的所有时间  |
      | executionStats.executionStages.executionTimeMillisEstimate             | 执行计划的执行完成时间     |
      | executionStats.executionStages.inputStage. executionTimeMillisEstimate | 执行计划下的子阶段执行完成时间 |
         
      
   
   2. 查看扫描条数。 如[表2]中三个条目相同为最佳。
       表2参数说明 
      | 参数名称                              | 描述         |
      |:---|:---|
      | executionStats. nReturned         | 匹配查询条件的文档数 |
      | executionStats .totalKeysExamined | 索引扫描条目数    |
      | executionStats .totalDocsExamined | 文档扫描条目数    |
         
      
   
   3. 查看Stage状态。
      性能较好的Stage状态组合如下：
      - Fetch+IDHACK
      
      - Fetch+ixscan,
      
      - Limit+（Fetch+ixscan）
      
      - PROJECTION+ixscan
      
      
      表3状态说明 
      | 状态名称       | 描述           |
      |:---|:---|
      | COLLSCAN   | 全表扫描         |
      | SORT       | 内存中进行排序      |
      | IDHACK     | 根据_id进行查询    |
      | TEXT       | 全文索引         |
      | COUNTSCAN  | 未用索引计数       |
      | FETCH      | 索引扫描         |
      | LIMIT      | 使用Limit限制返回数 |
      | SUBPLA     | 未用索引的$or查询阶段 |
      | PROJECTION | 使用索引计数       |
      | COUNT_SCAN | 使用索引计数       |
         
      
   
   
   
   
 
#### 优化方案
- 对于无索引覆盖的查询，则需要根据查询条件创建对应索引。
- 对于点查可以创建hash索引。
- 对于多字段查询，单字段重复度较高的场景，创建复合索引。
- 对于范围查找，结果集有序的查询，创建升序或者降序索引。
- 对于复合索引，由于复合索引是前缀排序查询，所以查询条件的顺序要与索引字段的顺序一致。
- 对于分区集合(表)、大集合(超过10万记录)，不要直接对大数据量的表使用模糊查询（即不能使用like）。这样会造成查询扫描的记录过多，建议先基于索引字段查询，过滤出较小的数据集后再使用模糊查询。
- 避免使用$not。MongoDB 并不会对缺失的数据进行索引，因此$not的查询条件将会要求在一个结果集中扫描所有记录。如果$not是唯一的查询条件，会对集合进行全表扫描。
- 用$and时把匹配最少结果的条件放在最前面，用$or时把匹配最多结果的条件放在最前面。
- 检查实例规格的性能基线，分析当前的业务需求是否达到上限，如已达当前实例性能瓶颈，请及时提升实例规格。
 
#### 相关文档
[使用索引](https://support.huaweicloud.com/bestpractice-dds/dds_0073.html)
