

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# 쿼리 계획 분석
<a name="performance-query-plan-analysis"></a>

설명 계획을 통한 쿼리 계획 분석은 Amazon DocumentDB 쿼리 성능에 대한 필수 인사이트를 제공합니다. executionStats를 사용한 쿼리 계획은 다음을 포함한 주요 지표를 보여줍니다.
+ 단계당 반환된 문서(nReturned)
+ 단계별 실행 시간(executionTimeMillisEstimate)
+ 계획 생성 기간(planningTimeMillis)

개발자는 쿼리 계획 출력을 검사하여 실행 패턴을 분석하고, 인덱스 사용률을 평가하고, 쿼리 파이프라인 단계에서 잠재적 최적화 기회를 식별할 수 있습니다.

쿼리 계획을 분석하려면 다음 형식으로 explain() 명령을 사용할 수 있습니다.

```
db.runCommand({explain: {query document}, verbosity: "executionStats"})
db.collection.find().explain("executionStats");
```

다음은 예제 작업입니다.

```
db.collection.find({ companyname: { '$eq': 'ANYCOMPANY' }, isDeleted: { '$eq': false } }).sort({"createdAt":1}).limit(2).explain("executionStats");
```

이 작업의 출력은 다음과 같이 표시됩니다.

```
{
  queryPlanner: {
    plannerVersion: 2,
    namespace: 'limit_test.test',
    winningPlan: {
      stage: 'LIMIT_SKIP',
      inputStage: {
        stage: 'SORT',
        sortPattern: { createdAt: 1 },
        inputStage: {
          stage: 'IXSCAN',
          indexName: 'companyname_1_createdAt_1_isDeleted_1',
          direction: 'forward',
          indexCond: {
            '$and': [
              { companyname: { '$eq': 'ANYCOMPANY' } },
              { isDeleted: { '$eq': false } }
            ]
          }
        }
      }
    }
  },
  indexFilterSet: false,
  indexFilterApplied: false,
  executionStats: {
    executionSuccess: true,
    executionTimeMillis: '4.186',
    planningTimeMillis: '3.909',
    executionStages: {
      stage: 'LIMIT_SKIP',
      nReturned: '2',
      executionTimeMillisEstimate: '0.199',
      inputStage: {
        stage: 'SORT',
        nReturned: '2',
        executionTimeMillisEstimate: '0.197',
        sortPattern: { createdAt: 1 },
        inputStage: {
          stage: 'IXSCAN',
          nReturned: '34',
          executionTimeMillisEstimate: '0.151',
          indexName: 'companyname_1_createdAt_1_isDeleted_1',
          direction: 'forward',
          indexCond: {
            '$and': [
              { companyname: { '$eq': 'ANYCOMPANY' } },
              { isDeleted: { '$eq': false } }
            ]
          }
        }
      }
    }
  },
  serverInfo: { host: 'demo-cluster', port: 27017, version: '5.0.0' },
  ok: 1,
  operationTime: Timestamp({ t: 1759915116, i: 1 })
}
```

다음은 Amazon DocumentDB 쿼리 실행 계획을 자세히 분석하여 각 구성 요소와 성능 특성을 분석한 것입니다.

## 전체 타이밍
<a name="overall-timing"></a>

executionTimeMillis는 계획 시간을 포함하여 쿼리에 걸린 총 시간을 나타냅니다.

planningTimeMillis는 쿼리에 소요된 총 계획 시간을 나타냅니다.

## 실행 단계
<a name="execution-stages"></a>

Amazon DocumentDB가 쿼리를 실행하는 데 사용하는 step-by-step 프로세스를 설명하여 다양한 작업을 통해 데이터가 흐르는 방식을 보여줍니다.

```
"executionStages": {
    "stage": "[STAGE_NAME]",
    "nReturned": "[NUMBER_OF_DOCS]",
    "executionTimeMillisEstimate": "[TIME]",
    "inputStage": {
        // Nested stages
    }
}
```

### 쿼리 계획의 공통 단계
<a name="common-stages"></a>

다음은 쿼리 계획의 일반적인 실행 단계입니다. 각 단계는 모든 단계에서 쿼리 성능을 평가하는 데 도움이 되도록 executionTimeMillisEstimate(실행 시간) 및 nReturned(문서 수) 지표를 반환합니다.

#### COLLSCAN(컬렉션 스캔)
<a name="collscan-stage"></a>
+ 문서별로 전체 컬렉션 문서를 스캔합니다.
+ nReturned: 컬렉션에서 일치하는 모든 문서를 반환합니다.
+ 인덱스를 사용할 수 없는 경우 표시되는 비용이 많이 드는 작업일 수 있습니다.

#### IXSCAN(인덱스 스캔)
<a name="ixscan-stage"></a>
+ 인덱스를 사용하여 일치하는 문서를 찾습니다.
+ nReturned: 인덱스를 기반으로 문서만 일치
+ 효율적인 작업, COLLSCAN보다 선호

#### SORT
<a name="sort-stage"></a>
+ 지정된 필드를 기준으로 문서를 정렬합니다.
+ 쿼리의 정렬 속성이 인덱스의 일부가 아닌 경우이 단계는 명시적으로 표시됩니다.
+ nReturned: 입력 문서와 동일한 번호
+ 대규모 결과 집합에 대해 메모리 집약적입니다. 최적화하려면 인덱스에 정렬 필드 이름을 추가합니다.

#### LIMIT\_SKIP
<a name="limit-skip-stage"></a>
+ 반환되고 건너뛴 문서 수를 제어합니다.
+ nReturned: LIMIT 값으로 제한됨
+ 페이지 매김 또는 LIMIT 작업에 사용됩니다.

#### 하위 스캔
<a name="subscan-stage"></a>
+ 중첩 쿼리 작업 수행
+ nReturned: 하위 쿼리 결과에 따라 다름
+ 여러 단계가 있는 복잡한 쿼리에 사용

executionTimeMillisEstimate는 최적화를 위한 좋은 후보입니다.

**참고**  
executionStats 파라미터는 현재 업데이트 및 삭제 명령을 지원하지 않습니다.

## 계획 실행 통계 설명의 docsExamined 이해
<a name="docs-examined"></a>

를 사용하여 쿼리를 실행하면 `explain("executionStats")` Amazon DocumentDB는 쿼리 결과를 생성하기 위해 스캔한 문서 수를 이해하는 데 도움이 되는 검사 지표를 제공합니다. 이러한 지표는 비효율적인 쿼리 계획을 식별하고 성능을 최적화하는 데 유용합니다.

**참고**  
Amazon DocumentDB 8.0.0 이상에서만 사용할 수 있습니다.

### 필드
<a name="docs-examined-fields"></a>


| 필드 | 설명 | 수준 | 
| --- | --- | --- | 
| totalDocsExamined | 모든 실행 단계에서 검사한 총 문서 수입니다. | 최상위 executionStats | 
| docsExamined | 특정 실행 단계에서 검사한 문서 수입니다. | 단계 수준 | 

`docsExamined` 필드는 다음 단계에 나타납니다.


| 단계 | 설명 | 
| --- | --- | 
| 콜스캔 | 컬렉션 스캔. 컬렉션의 모든 문서가 검사됩니다. | 
| ISSCAN | 인덱스 스캔. 인덱스 조건과 일치하는 문서만 검사됩니다. | 
| FETCH | 최적화 프로그램이 IXSCAN과 별도의 단계에서 문서를 검색하면 FETCH 단계는 docsExamined를 보고합니다. 인덱스 스캔 계획에서 하위 IXSCAN 단계는 docsExamined를 보고하지 않습니다. $lookup 계획에서 FETCH 단계와 하위 단계 모두 docsExamined를 보고할 수 있습니다. | 

**참고**  
`docsExamined`는 문서에 액세스하지 않고 쿼리가 인덱스에서 완전히 충족되기 때문에 IXONLYSCAN 단계에 나타나지 않습니다.

### 계획 executionStats 출력 설명에 docsExamined 표시
<a name="docs-examined-examples"></a>

다음 예제에서는 500,000개의 문서가 있는 컬렉션을 사용하고 다양한 쿼리 실행 단계에서가 어떻게 `docsExamined` 변경되는지 보여줍니다.

샘플 데이터 생성:

```
for (let i = 0; i < 500000; i++) {
    db.coll.insertOne({ number: i, arr: [i, [i+1]], value: "test", bool: i % 2 === 0 });
}
```

#### 컬렉션 스캔(COLLSCAN)
<a name="docs-examined-collscan"></a>

인덱스가 없으면 Amazon DocumentDB는 전체 컬렉션 스캔을 수행합니다.

```
db.coll.find({ "number": { "$lt": 500 } }).explain("executionStats").executionStats
```

출력:

```
{
    "executionSuccess" : true,
    "nReturned" : "500",
    "executionTimeMillis" : "282.055",
    "planningTimeMillis" : "0.085",
    "totalDocsExamined" : "500000",
    "executionStages" : {
        "stage" : "COLLSCAN",
        "nReturned" : "500",
        "executionTimeMillisEstimate" : "281.915",
        "docsExamined" : "500000",
        "filter" : {
            "number" : {
                "$lt" : 500
            }
        }
    }
}
```

500,000개의 모든 문서를 검사하여 500개의 결과를 반환했습니다. 숫자 필드에 인덱스를 생성하면 이를 개선할 수 있습니다.

#### 인덱스 스캔(IXSCAN)
<a name="docs-examined-ixscan"></a>

```
db.coll.createIndex({ number: 1 });
db.coll.find({ "number": { "$lt": 5000 } }).explain("executionStats").executionStats
```

출력:

```
{
    "executionSuccess" : true,
    "nReturned" : "5000",
    "executionTimeMillis" : "3.047",
    "planningTimeMillis" : "0.296",
    "totalDocsExamined" : "5000",
    "executionStages" : {
        "stage" : "IXSCAN",
        "nReturned" : "5000",
        "executionTimeMillisEstimate" : "2.576",
        "indexName" : "number_1",
        "direction" : "forward",
        "docsExamined" : "5000",
        "indexCond" : {
            "$and" : [
                {
                    "number" : {
                        "$lt" : 5000
                    }
                }
            ]
        }
    }
}
```

인덱스를 사용하면 반환된 수와 일치하는 500,000개 문서 중 5,000개만 검사하고 가져왔습니다. 인덱스 조건은 쿼리와 일치하지 않는 495,000개의 문서를 필터링했습니다.

#### 잔차 필터를 사용한 인덱스 스캔
<a name="docs-examined-ixscan-residual"></a>

```
db.coll.find({ "number": { "$lt": 5000 }, "arr": { "$gt": 4000 } }).explain("executionStats").executionStats
```

출력:

```
{
    "executionSuccess" : true,
    "nReturned" : "999",
    "executionTimeMillis" : "15.367",
    "planningTimeMillis" : "0.115",
    "totalDocsExamined" : "5000",
    "executionStages" : {
        "stage" : "IXSCAN",
        "nReturned" : "999",
        "executionTimeMillisEstimate" : "15.170",
        "indexName" : "number_1",
        "direction" : "forward",
        "docsExamined" : "5000",
        "indexCond" : {
            "$and" : [
                {
                    "number" : {
                        "$lt" : 5000
                    }
                }
            ]
        },
        "filter" : {
            "arr" : {
                "$gt" : 4000
            }
        }
    }
}
```

인덱스 조건이 500,000개 중 5,000개의 문서와 일치하면의 잔차 필터가 결과를 999로 `arr` 줄였습니다. `docsExamined` 값 5,000은 인덱스 조건 이후이지만 잔차 필터가 적용되기 전에 검사된 모든 문서를 반영합니다.

#### IXSCAN을 사용하여 가져오기
<a name="docs-examined-fetch-ixscan"></a>

```
db.coll.find({ "$or": [{ "number": { "$lt": 100000 } }, { "number": { "$gt": 400000 } }] }).explain("executionStats").executionStats
```

출력:

```
{
    "executionSuccess" : true,
    "nReturned" : "199999",
    "executionTimeMillis" : "899.801",
    "planningTimeMillis" : "0.183",
    "totalDocsExamined" : "199999",
    "executionStages" : {
        "stage" : "FETCH",
        "nReturned" : "199999",
        "executionTimeMillisEstimate" : "894.141",
        "docsExamined" : "199999",
        "inputStage" : {
            "stage" : "IXOR",
            "nReturned" : "0",
            "executionTimeMillisEstimate" : "874.897",
            "inputStages" : [
                {
                    "stage" : "IXSCAN",
                    "nReturned" : "100000",
                    "executionTimeMillisEstimate" : "462.208",
                    "indexName" : "number_1",
                    "indexCond" : {
                        "$and" : [
                            {
                                "number" : {
                                    "$lt" : 100000
                                }
                            }
                        ]
                    }
                },
                {
                    "stage" : "IXSCAN",
                    "nReturned" : "99999",
                    "executionTimeMillisEstimate" : "412.684",
                    "indexName" : "number_1",
                    "indexCond" : {
                        "$and" : [
                            {
                                "number" : {
                                    "$gt" : 400000
                                }
                            }
                        ]
                    }
                }
            ]
        }
    }
}
```

Amazon DocumentDB 옵티마이저가 가져오기 단계를 사용하여 문서를 검색하는 경우 FETCH 단계는를 보고합니다`docsExamined`. 하위 IXSCAN 단계는 문서에 직접 액세스하지 않고 인덱스 키만 스캔`docsExamined`하므로 보고하지 않습니다.

#### 집계 조회가 포함된 FETCH
<a name="docs-examined-fetch-lookup"></a>

```
db.coll.explain("executionStats").aggregate([
    { $match: { "number": { "$lt": 5 } } },
    { $lookup: { from: "coll", pipeline: [{ $match: { "number": { "$lt": 3 } } }], as: "sub" } }
]).executionStats
```

출력:

```
{
    "executionSuccess" : true,
    "nReturned" : "5",
    "executionTimeMillis" : "0.525",
    "planningTimeMillis" : "0.327",
    "totalDocsExamined" : "9",
    "executionStages" : {
        "stage" : "NESTED_LOOP_LOOKUP",
        "nReturned" : "5",
        "executionTimeMillisEstimate" : "0.163",
        "inputStages" : [
            {
                "stage" : "IXSCAN",
                "nReturned" : "5",
                "executionTimeMillisEstimate" : "0.039",
                "indexName" : "number_1",
                "direction" : "forward",
                "docsExamined" : "5",
                "indexCond" : {
                    "$and" : [
                        {
                            "number" : {
                                "$lt" : 5
                            }
                        }
                    ]
                }
            },
            {
                "stage" : "FETCH",
                "nReturned" : "1",
                "executionTimeMillisEstimate" : "0.009",
                "docsExamined" : "1",
                "inputStage" : {
                    "stage" : "AGGREGATE",
                    "nReturned" : "1",
                    "executionTimeMillisEstimate" : "0.044",
                    "inputStage" : {
                        "stage" : "IXSCAN",
                        "nReturned" : "3",
                        "executionTimeMillisEstimate" : "0.013",
                        "indexName" : "number_1",
                        "direction" : "forward",
                        "docsExamined" : "3",
                        "indexCond" : {
                            "$and" : [
                                {
                                    "number" : {
                                        "$lt" : 3
                                    }
                                }
                            ]
                        }
                    }
                }
            }
        ]
    }
}
```

외부 IXSCAN은 일치하는 번호 < 5개 문서 5개를 검사했습니다. 내부 IXSCAN은 일치하는 번호 < 3인 문서 3개를 검사했고 FETCH 단계에서는 집계된 결과 1개를 검사했습니다. 9`totalDocsExamined`의는 모든 단계(5 \+ 3 \+ 1)의 합계입니다.