

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

# 쿼리 플래너 v2
<a name="query-planner"></a>

새로운 Amazon DocumentDB용 쿼리 플래너(플래너 버전 2.0)는 고급 쿼리 최적화 기능과 향상된 성능을 제공합니다. Amazon DocumentDB 5.0용 플래너 버전 2.0은 인덱스와 함께 `find` 및 `update` 연산자를 사용할 때 이전 버전보다 최대 10배 향상된 성능을 제공합니다. 성능 개선은 주로 보다 최적화된 인덱스 계획 사용 및 부정 연산자(`$neq`, `$nin`), 중첩 `$elementMatch`와 같은 연산자에 대한 인덱스 스캔 지원 활성화에서 비롯됩니다. 플래너 버전 2.0 쿼리는 개선된 비용 추정 기법, 최적화된 알고리즘 및 향상된 안정성을 통해 더 빠르게 실행됩니다. 플래너 버전 2.0은 계획 캐시 필터 API도 지원하므로 플래너 안정성이 향상됩니다. 이 기능을 통해 Amazon DocumentDB 5.0은 이제 다양한 버전의 쿼리 플래너 중에서 선택할 수 있는 기능을 제공합니다.

**Topics**
+ [사전 조건](#nqp-prerequisites)
+ [플래너 버전 2.0을 기본 쿼리 플래너로 선택](#second-concept-chapter)
+ [모범 사례](#nqp-best-practices)
+ [제한 사항](#nqp-limitations)
+ [`Find` 및 `Update` 연산자에 대한 개선 사항](#operator-improvements)
+ [계획 캐시 필터 API](#plan-cache-filter-api)
+ [플래너 버전 1.0, 2.0 및 MongoDB 간의 잠재적 동작 차이](#planner-behavior-differences)
+ [플래너 버전 2.0은 동작 격차를 MongoDB와 연결합니다.](#planner-v2-mongo-gap-bridge)

## 사전 조건
<a name="nqp-prerequisites"></a>

플래너 버전 2.0에는 다음 사전 조건이 적용됩니다.
+ 플래너 버전 2.0은 엔진 버전 5.0을 사용할 수 있는 모든 리전에서 제공됩니다.
+ 버전 2.0을 기본 쿼리 플래너로 사용하도록 선택하려면 클러스터가 Amazon DocumentDB 버전 5.0의 엔진 패치 버전 3.0.15902 이상에 있어야 합니다. 최신 엔진 버전 패치로 업데이트하는 단계는 [클러스터의 엔진 버전에 대한 패치 업데이트 수행](db-cluster-version-upgrade.md) 섹션을 참조하세요.
+ 플래너 버전 2.0을 기본 쿼리 플래너로 설정하려면 클러스터 파라미터 그룹을 업데이트할 수 있는 IAM 권한이 필요합니다.
+ Amazon DocumentDB 8.0의 경우 플래너 버전 3.0이 기본 쿼리 플래너입니다. 세부 정보는 [쿼리 플래너 v3](query-planner-v3.md) 섹션을 참조하세요.

## 플래너 버전 2.0을 기본 쿼리 플래너로 선택
<a name="second-concept-chapter"></a>

다음 단계에 따라 콘솔 또는 CLI에서 2.0을 기본 쿼리 플래너로 선택합니다.
+ [Amazon DocumentDB 클러스터 파라미터 수정](cluster_parameter_groups-parameters.md)의 단계에 따라 클러스터의 파라미터 그룹을 수정합니다.
+ 'plannerVersion'이라는 파라미터의 경우 값을 플래너 버전을 나타내는 2.0으로 변경합니다.
+ **즉시 적용**을 선택합니다(**재부팅 시 적용**을 선택하는 경우 다음에 클러스터를 재부팅할 때까지 선택이 적용되지 않음).

## 모범 사례
<a name="nqp-best-practices"></a>

예상 결과를 얻으려면 플래너 버전 2.0을 적용할 때 다음 모범 사례를 사용하세요.
+ 글로벌 클러스터에서 두 리전의 클러스터 파라미터 그룹에서 동일한 `plannerVersion` 값(1.0 또는 2.0)을 선택합니다. 기본 리전 및 보조 리전에서 다른 플래너 버전을 선택하면 쿼리 동작과 성능이 일관되지 않을 수 있습니다.
+ 예약된 유지 관리 기간 동안 또는 감소된 트래픽 기간 동안 플래너 버전 2.0으로 업데이트하면 워크로드가 활발하게 실행 중일 때 플래너 버전이 변경되는 경우 오류율이 증가할 수 있으므로 중단이 가장 적습니다.
+ 플래너 버전 2.0은 MongoDB 쉘 버전 5.0에서 가장 최적으로 작동합니다.

## 제한 사항
<a name="nqp-limitations"></a>

플래너 버전 2.0에는 다음과 같은 제한이 적용됩니다.
+ 플래너 버전 2.0은 탄력적 클러스터에서 지원되지 않으며, 플래너 버전 1.0으로 대체됩니다.
+ 플래너 버전 2.0은 집계 및 고유 명령에 대해 지원되지 않으며, 플래너 버전 1.0으로 대체됩니다.
+ 정규식, 텍스트 검색, 지리 공간, json 스키마 또는 필터의 `$expr`이 포함된 쿼리는 플래너 버전 2.0의 계획 캐시 필터에서 지원되지 않습니다.

## `Find` 및 `Update` 연산자에 대한 개선 사항
<a name="operator-improvements"></a>

플래너 버전 2.0은 `find`, `update`, `delete`, `find-and-modify` 명령을 포함한 기본 작업을 최적화합니다. 다음의 탭 섹션에서는 인덱스에 대한 향상된 기능과 플래너 버전 2.0의 쿼리 성능 개선을 보여줍니다.

------
#### [ Enhanced index support ]
+ 플래너 버전 2.0에는 `$nin`, `$ne`, `$not {eq}`, `$not {in}` 및 `$type`, `$elemMatch`를 포함한 부정 연산자에 대한 인덱스 지원이 추가되었습니다.

  ```
  Sample Document: { "x": 10, "y": [1, 2, 3] }
  
  db.foo.createIndex({ "x": 1, "y": 1 })
  db.foo.find({ "x": {$nin: [20, 30] }})
  db.foo.find({"x":{ $type: "string" }})
  
  db.foo.createIndex({"x.y": 1})
  db.foo.find({"x":{$elemMatch:{"y":{$elemMatch:{"$gt": 3 }}}}})
  ```
+  플래너 버전 2.0은 `$exists`가 쿼리 표현식에 없는 경우에도 희소 인덱스 또는 부분 인덱스를 사용합니다.

  ```
  Sample Document: {"name": "Bob", "email": "example@fake.com" }
  
  Using Planner Version 1.0, you can specify the command as shown below:
  db.foo.find({email: "example@fake.com", email: {$exists: true}})
  
  Using Planner Version 2.0, you can specify command without $exists:
  db.foo.find({ email: "example@fake.com" })
  ```
+ 플래너 버전 2.0은 쿼리 조건이 부분 인덱스 필터 표현식과 정확히 일치하지 않는 경우에도 부분 인덱스를 활용합니다.

  ```
  Sample Document: {"name": "Bob", "age": 34}
  db.foo.createIndex({"age":1},{partialFilterExpression:{"age":{$lt:50}}})
  
  With Planner Version 1.0, index is used only when the query condition meets the partial
   index filter criterion:
       db.foo.find({"age":{$lt:50}})
  
  With Planner Version 2.0, index is used even when the query condition doesn’t meet the index
  criterion:
  db.foo.find({"age":{$lt:30}})
  ```
+ 플래너 버전 2.0은 \$1elemMatch 쿼리와 함께 부분 인덱스 스캔을 활용합니다.

  ```
  Sample Document: {"name": "Bob", "age": [34,35,36]}
  db.foo.createIndex({"age":1},{partialFilterExpression:{"age":{$lt:50,$gt:20}}})
  db.foo.find({age:{$elemMatch:{$lt:50,$gt:20}}})
  ```
+ 플래너 버전 2.0에는 애플리케이션 코드에 `$hint`를 제공할 필요 없이 `$regex`에 대한 인덱스 스캔 지원이 포함되어 있습니다. `$regex`는 접두사 검색에서만 인덱스를 지원합니다.

  ```
  Sample Document: { "x": [1, 2, 3], "y": "apple" }
  db.foo.createIndex({ "x": 1, "y": 1 })
  db.foo.find({"y":{ $regex: "^a" }})
  ```
+ 플래너 버전 2.0은 다중 키 필드에 대한 등식 조건을 사용하여 다중 키 인덱스와 관련된 쿼리의 성능을 개선합니다.

  ```
  Sample Document: {"x": [1, 2, 3],
  "y": 5}
  db.foo.createIndex({"x": 1, "y":1})
  db.foo.find({"x": 2,
  "y": {$gt: 1}}).limit(1)
  ```
+ 플래너 버전 2.0은 특히 문서가 8KB를 초과하는 컬렉션에서 여러 필터가 포함된 쿼리의 성능을 개선합니다.

  ```
  Sample Document: {"x": 2,
  "y": 4,
  "z": 9,
  "t": 99}
  db.foo.find({$and: [{"x": {$gt : 1}, "y": {$gt : 3}, "z": {$lt : 10},
  "t":{$lt : 100}}]})
  ```
+ 플래너 버전 2.0은 정렬 단계를 제거하여 복합 인덱스와 함께 `$in` 연산자를 사용할 경우의 쿼리 성능을 개선합니다.

  ```
  Sample Document: {"x": 2,
  "y": 4,
  "z": 9,
  "t": 99}
  db.foo.createIndex({"x":1, "y":1})
  db.foo.find({"x":2,
  "y":$in:[1,2,3,4]}).sort({x:1,y:1})
  ```

  또한 `$in` 요소와 함께 다중 키 인덱스를 사용하는 쿼리의 성능을 개선합니다.

  ```
  Sample Document: {"x": [1, 2, 3]}
  db.foo.createIndex({"x": 1})
  db.foo.find("x":{$in:[>100 elements]})
  ```

------
#### [ Query performance improvements ]
+ 플래너 버전 2.0은 특히 문서가 8KB를 초과하는 컬렉션에서 여러 필터가 포함된 쿼리의 성능을 개선합니다.

  ```
  Sample Document: {"x": 2,
  "y": 4,
  "z": 9,
  "t": 99}
  db.foo.find({$and: [{"x": {$gt : 1}, "y": {$gt : 3}, "z": {$lt : 10},
  "t":{$lt : 100}}]})
  ```
+ 플래너 버전 2.0은 정렬 단계를 제거하여 복합 인덱스와 함께 `$in` 연산자를 사용할 경우의 쿼리 성능을 개선합니다.

  ```
  Sample Document: {"x": 2,
  "y": 4,
  "z": 9,
  "t": 99}
  db.foo.createIndex({"x":1, "y":1})
  db.foo.find({"x":2,
  "y":$in:[1,2,3,4]}).sort({x:1,y:1})
  ```

  또한 `$in` 요소와 함께 다중 키 인덱스를 사용하는 쿼리의 성능을 개선합니다.

  ```
  Sample Document: {"x": [1, 2, 3]}
  db.foo.createIndex({"x": 1})
  db.foo.find("x":{$in:[>100 elements]})
  ```

------

## 계획 캐시 필터 API
<a name="plan-cache-filter-api"></a>

**참고**  
텍스트 인덱스는 계획 캐시 필터에서 지원되지 않습니다.
+ 플래너 버전 2.0에는 특정 쿼리 셰이프에서 사용할 수 있는 인덱스 목록을 지정할 수 있는 인덱스 필터 기능에 대한 지원이 추가되었습니다. 이 기능은 API를 통해 액세스할 수 있으며 서버 측에서 제어할 수 있습니다. 쿼리 회귀가 발생하는 경우 이 기능을 사용하면 애플리케이션 코드를 수정하지 않고도 문제를 완화할 수 있는 더 빠르고 유연한 옵션이 제공됩니다.

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

  컬렉션의 모든 필터를 나열하려면 다음 명령을 사용합니다.

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

  이 명령은 컬렉션의 모든 인덱스 필터를 표시합니다. 출력 예시:

  ```
  {
  "filters" : [
  {
  "query" : {a: "@", b: "@"},
  "sort" : {a: 1},
  "indexes" : [
  <index1>,
  ...
  ]
  },
  ...
  ],
  "ok": 1
  }
  ```
+ `explain` 명령 출력에서 `indexFilterSet` 및 `indexFilterApplied`의 두 새 필드를 사용하여 플래너 버전 2.0의 인덱스 필터링을 분석할 수 있습니다. 컬렉션에 쿼리 셰이프와 일치하는 인덱스 필터가 설정된 경우는 `indexFilterSet`는 "true"로 설정됩니다. `indexFilterApplied`는 쿼리가 인덱스 필터를 적용하고 필터 목록에서 인덱스를 사용하여 계획을 선택한 경우에만 "true"로 설정됩니다.

  다음 명령을 사용하여 인덱스 필터를 지울 수 있습니다.

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

  "foo" 모음의 모든 필터를 지우려면 다음 명령을 사용합니다.

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

  정렬을 사용하여 특정 쿼리 셰이프를 지우려면 `planCacheListFilters`의 출력에서 쿼리 셰이프를 복사하여 붙여넣으면 됩니다.

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

  정렬 기준으로 지정할 필드가 있는 특정 쿼리 셰이프를 지우려면 `planCacheListFilters`의 출력에서 쿼리 셰이프를 복사하여 붙여넣으면 됩니다.

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

## 플래너 버전 1.0, 2.0 및 MongoDB 간의 잠재적 동작 차이
<a name="planner-behavior-differences"></a>

일부 극단적인 경우에는 플래너 버전 2.0이 MongoDB의 결과와 약간 다른 결과를 생성할 수 있습니다. 이 섹션에서는 이러한 가능성의 몇 가지 예를 살펴봅니다.

------
#### [ \$1(update) and \$1(projection) ]
+ 경우에 따라 MongoDB의 `$(update)` 및 `$(projection)` 연산자는 Amazon DocumentDB의 플래너 버전 1.0과 다르게 작동할 수 있습니다. 다음은 일부 예제입니다.

  ```
  db.students_list.insertMany( [ { _id: 5, student_ids: [ 100, 200 ], grades: [ 95, 100 ], grad_year: [ 2024, 2023 ] } ] )
  ```

  ```
  db.students_list.updateOne({ student_ids: 100, grades: 100, grad_year: 2024 },
  { $set: { “grad_year.$”: 2025 } }
  ```
  + **플래너 버전 1.0** - 2022년 필드 업데이트
  + **MongoDB** - 2022년 필드 업데이트
  + **플래너 버전 2.0** - 2021년 필드 업데이트
+ 

  ```
  db.col.insert({x:[1,2,3]})
  db.col.update({$and:[{x:1},{x:3}]},{$set:{"x.$":500}})
  ```
  + **플래너 버전 1.0** - 일치하는 첫 번째 요소를 무작위로 업데이트
  + **MongoDB** - 일치하는 첫 번째 요소를 무작위로 업데이트
  + **플래너 버전 2.0** - 업데이트하지 않음
+ 

  ```
  db.col.insert({x:[1,2,3]})
  db.col.find()
  ```
  + **플래너 버전 1.0** - 일치하는 요소를 무작위로 선택
  + **MongoDB** - 일치하는 요소를 무작위로 선택
  + **플래너 버전 2.0** - 선택하지 않음
+ 

  ```
  db.col.insert({x:100})
  db.col.update({x:100},{x:100})
  ```
  + **플래너 버전 1.0** - nModified 개수 변경
  + **MongoDB** - nModified 개수 변경
  + **플래너 버전 2.0** - 동일한 값으로 업데이트해도 nModified 개수는 변경되지 않습니다.
+ `$(update)` 연산자를 `$setOnInsert`와 함께 사용하면 플래너 버전 1.0 및 MongoDB에서 오류가 발생하지만 플래너 버전 2.0에서는 오류가 발생하지 않습니다.
+ 존재하지 않는 필드의 이름을 `$field`로 변경하면 플래너 버전 2.0에서 오류가 발생하지만 플래너 버전 1.0 및 MongoDB에서는 업데이트를 생성하지 않습니다.

------
#### [ Index behavior ]
+ 플래너 버전 2.0은 `$hint`가 적합하지 않은 인덱스와 함께 적용될 때 오류가 발생하지만 플래너 버전 1.0 및 MongoDB에서는 오류가 발생하지 않습니다.

  ```
  // Insert
  db.col.insert({x:1})
  db.col.insert({x:2})
  db.col.insert({x:3})
  
  // Create index on x with partialFilter Expression {x:{$gt:2}}
  db.col.createIndex({x:1},{partialFilterExpression:{x:{$gt:2}}})
  
  // Mongodb allows hint on the following queries
  db.col.find({x:1}).hint("x_1")
  // result is no documents returned because {x:1} is not indexed by the partial index
  // Without $hint mongo should return {x:1}, thus the difference in result between COLSCAN and IXSCAN
  
  DocumentDB will error out when $hint is applied on such cases.
  db.col.find({x:1}).hint("x_1")
  Error: error: {
      "ok" : 0,
      "operationTime" : Timestamp(1746473021, 1),
      "code" : 2,
      "errmsg" : "Cannot use Hint for this Query. Index is multi key index , partial index or sparse index and query is not optimized to use this index."
  }
  
  rs0:PRIMARY> db.runCommand({"planCacheSetFilter": "col", "query": { location: {$nearSphere: {$geometry: {type: "Point", coordinates: [1, 1]}}}}, "indexes": ["name_1"]})
  {
      "ok" : 0,
      "operationTime" : Timestamp(1750815778, 1),
      "code" : 303,
      "errmsg" : "Unsupported query shape for index filter $nearSphere"
  }
  ```
+ `$near`는 플래너 버전 2.0에서 `$hint({“$natural”:1})`를 사용할 수 없습니다.

  ```
  // indexes present are index on x and geo index
  
  rs0:PRIMARY> db.usarestaurants.getIndexes()
  [
      {
          "v" : 4,
          "key" : {
              "_id" : 1
          },
          "name" : "_id_",
          "ns" : "test.usarestaurants"
      },
      {
          "v" : 4,
          "key" : {
              "location" : "2dsphere"
          },
          "name" : "location_2dsphere",
          "ns" : "test.usarestaurants",
          "2dsphereIndexVersion" : 1
      }
  ]
  
  // Planner Version 2.0 will throw an error when $hint is applied with index "x_1"
  rs0:PRIMARY> db.usarestaurants.find({    "location":{       "$nearSphere":{          "$geometry":{             "type":"Point",             "coordinates":[                -122.3516,                47.6156             ]          },          "$minDistance":1,          "$maxDistance":2000       }    } }, {    "name":1 }).hint({"$natural": 1})
  Error: error: {
      "ok" : 0,
      "operationTime" : Timestamp(1746475524, 1),
      "code" : 291,
      "errmsg" : "unable to find index for $geoNear query"
  }
  
  // Planner Version 1.0 and MongoDB will not throw an error
   db.usarestaurants.find({    "location":{       "$nearSphere":{          "$geometry":{             "type":"Point",             "coordinates":[                -122.3516,                47.6156             ]          },          "$minDistance":1,          "$maxDistance":2000       }    } }, {    "name":1 }).hint({"$natural": 1})
  { "_id" : ObjectId("681918e087dadfd99b7f0172"), "name" : "Noodle House" }
  ```
+ MongoDB는 전체 정규식 인덱스 스캔을 지원하지만 플래너 버전 2.0은 접두사 필드에서만 정규식 인덱스 스캔을 지원합니다.

  ```
  // index on x
  db.col.createIndex({x:1})
  
  // index scan is used only for prefix regexes
  rs0:PRIMARY> db.col.find({x: /^x/}).explain()
  {
      "queryPlanner" : {
          "plannerVersion" : 2,
          "namespace" : "test.col",
          "winningPlan" : {
              "stage" : "IXSCAN",
              "indexName" : "x_1",
              "direction" : "forward",
              "indexCond" : {
                  "$and" : [
                      {
                          "x" : {
                              "$regex" : /^x/
                          }
                      }
                  ]
              },
              "filter" : {
                  "x" : {
                      "$regex" : /^x/
                  }
              }
          }
      },
      "indexFilterSet" : false,
      "indexFilterApplied" : false,
      "ok" : 1,
      "operationTime" : Timestamp(1746474527, 1)
  }
  
  // COLSCAN is used for non-prefix regexes
  rs0:PRIMARY> db.col.find({x: /x$/}).explain()
  {
      "queryPlanner" : {
          "plannerVersion" : 2,
          "namespace" : "test.col",
          "winningPlan" : {
              "stage" : "COLLSCAN",
              "filter" : {
                  "x" : {
                      "$regex" : /x$/
                  }
              }
          }
      },
      "indexFilterSet" : false,
      "indexFilterApplied" : false,
      "ok" : 1,
      "operationTime" : Timestamp(1746474575, 1)
  ```
+ 플래너 버전 2.0에서 계획 캐시 필터를 사용하는 경우 MongoDB에 비해 몇 가지 고유한 차이점이 있습니다. 플래너 버전 2.0은 계획 캐시 필터를 사용한 “projection” 및 “collation” 지정을 지원하지 않지만 MongoDB에서는 지원합니다. 그러나 MongoDB 인덱스 필터는 인 메모리 전용이며 다시 시작한 후 손실됩니다. 플래너 버전 2.0은 재시작 및 패치를 통해 인덱스 필터를 유지합니다.

------
#### [ Others ]
+ 플래너 버전 2.0을 사용할 때 DML 감사 로그의 형식은 플래너 버전 1.0과 약간 다릅니다.

  ```
  command -  db.col.find({x:1})
  
  ************** Audit logs generated ******************
  
  // v1 format for dml audit logs
  {"atype":"authCheck","ts":1746473479983,"timestamp_utc":"2025-05-05 19:31:19.983","remote_ip":"127.0.0.1:47022","users":[{"user":"serviceadmin","db":"test"}],"param":{"command":"find","ns":"test.col","args":{"batchSize":101,"filter":{"x":1},"find":"col","limit":18446744073709551615,"lsid":{"id":{"$binary":"P6RCGz9ZS4iWBSSHWXW15A==","$type":"4"},"uid":{"$binary":"6Jo8PisnEi3dte03+pJFjdCyn/5cGQL8V2KqaoWsnk8=","$type":"0"}},"maxScan":18446744073709551615,"singleBatch":false,"skip":0,"startTransaction":false},"result":0}}
  
  // v2 formal for dml audit logs
  {"atype":"authCheck","ts":1746473583711,"timestamp_utc":"2025-05-05 19:33:03.711","remote_ip":"127.0.0.1:37754","users":[{"user":"serviceadmin","db":"test"}],"param":{"command":"find","ns":"test.col","args":{"find":"col","filter":{"x":1},"lsid":{"id":{"$binary":"nJ88TGCSSd+BeD2+ZtrhQg==","$type":"4"}},"$db":"test"},"result":0}}
  ```
+ 설명 계획의 일부로 사용되는 인덱스 조건:

  ```
  rs0:PRIMARY> db.col.createIndex({index1:1})
  {
  	"createdCollectionAutomatically" : false,
  	"numIndexesBefore" : 1,
  	"numIndexesAfter" : 2,
  	"ok" : 1,
  	"operationTime" : Timestamp(1761149251, 1)
  }
  ```

  플래너 버전 2.0은 인덱스 조건 및 필터를 표시하는 계획 출력을 설명합니다.

  ```
  rs0:PRIMARY> db.col.find({$and:[{price:{$eq:300}},{item:{$eq:"apples"}}]}).explain()
  {
  	"queryPlanner" : {
  		"plannerVersion" : 2,
  		"namespace" : "test.col",
  		"winningPlan" : {
  			"stage" : "IXSCAN",
  			"indexName" : "price_1",
  			"direction" : "forward",
  			"indexCond" : {
  				"$and" : [
  					{
  						"price" : {
  							"$eq" : 300
  						}
  					}
  				]
  			},
  			"filter" : {
  				"$and" : [
  					{
  						"item" : {
  							"$eq" : "apples"
  						}
  					}
  				]
  			}
  		}
  	},
  	"indexFilterSet" : false,
  	"indexFilterApplied" : false,
  	"ok" : 1,
  	"operationTime" : Timestamp(1761149497, 1)
  }
  ```

  플래너 버전 1.0은 계획 출력을 설명합니다.

  ```
  rs0:PRIMARY> db.col.find({$and:[{price:{$eq:300}},{item:{$eq:"apples"}}]}).explain()
  {
  	"queryPlanner" : {
  		"plannerVersion" : 1,
  		"namespace" : "test.col",
  		"winningPlan" : {
  			"stage" : "IXSCAN",
  			"indexName" : "price_1",
  			"direction" : "forward"
  		}
  	},
  	"ok" : 1,
  	"operationTime" : Timestamp(1761149533, 1)
  }
  ```

------

## 플래너 버전 2.0은 동작 격차를 MongoDB와 연결합니다.
<a name="planner-v2-mongo-gap-bridge"></a>

플래너 버전 2.0이 MongoDB의 동작 격차를 해소하는 몇 가지 영역이 있습니다.
+ 플래너 버전 2.0은 `$elemMatch`의 평면화된 배열에서 숫자 인덱스 조회를 허용합니다.

  ```
  doc: {"x" : [ [ { "y" : 1 } ] ] }
  
  // Planner Version 2 and mongo
  > db.bar.find({"x.0": {$elemMatch: {y: 1}}})
  { "_id" : ObjectId("68192947945e5846634c455a"), "x" : [ [ { "y" : 1 } ] ] }
  > db.bar.find({"x": {$elemMatch: {"0.y": 1}}})
  { "_id" : ObjectId("68192947945e5846634c455a"), "x" : [ [ { "y" : 1 } ] ] }
  
  //Whereas Planner Version 1 wouldn't return any results.
  > db.bar.find({"x.0": {$elemMatch: {y: 1}}})
  > db.bar.find({"x": {$elemMatch: {"0.y": 1}}})
  ```
+ 플래너 버전 1.0은 프로젝션에서 문자열을 제외했지만 플래너 버전 2.0의 동작은 MongoDB와 일치하고 이를 리터럴 값으로 취급합니다.”

  ```
  // Planner V2/ MongoDB
  > db.col.find()
  { "_id" : ObjectId("681537738aa101903ed2fe05"), "x" : 1, "y" : 1 }
  > db.col.find({},{x:"string"})
  { "_id" : ObjectId("681537738aa101903ed2fe05"), "x" : "string" }
  
  // Planner V1 treats strings as exclude in projection
  rs0:PRIMARY> db.col.find()
  { "_id" : ObjectId("68153744d42969f11d5cca72"), "x" : 1, "y" : 1 }
  rs0:PRIMARY> db.col.find({},{x:"string"})
  { "_id" : ObjectId("68153744d42969f11d5cca72"), "y" : 1 }
  ```
+ MongoDB와 같은 플래너 버전 2.0은 동일한 필드 “x” 및 “x.a”에서 프로젝션을 허용하지 않습니다.

  ```
  // Planner version 2/MongoDB will error out
  > db.col.find()
  { "_id" : ObjectId("68153da2012265816bc9ba23"), "x" : [ { "a" : 1 }, 3 ] }
   db.col.find({},{"x.a":1,"x":1}) // error
   
  // Planner Version 1 does not error out
  db.col.find()
  { "_id" : ObjectId("68153da2012265816bc9ba23"), "x" : [ { "a" : 1 }, 3 ] }
  
  db.col.find({},{"x.a":1,"x":1})
  { "_id" : ObjectId("68153d60143af947c720d099"), "x" : [ { "a" : 1 }, 3 ] }
  ```
+ MongoDB와 같은 플래너 버전 2.0은 하위 문서에 대한 프로젝션을 허용합니다.

  ```
  // Planner Version2/MongoDB supports projections on subdocuments
   db.col.find()
  { "_id" : ObjectId("681542d8f35ace71f0a50004"), "x" : [ { "y" : 100 } ] }
  > db.col.find({},{"x":{"y":1}})
  { "_id" : ObjectId("681542b7a22d548e4ac9ddea"), "x" : [ { "y" : 100 } ] }
  
  // Planner V1 throws error if projection is subdocument
   db.col.find()
  { "_id" : ObjectId("681542d8f35ace71f0a50004"), "x" : [ { "y" : 100 } ] }
  rs0:PRIMARY> db.col.find({},{"x":{"y":1}})
  Error: error: {
      "ok" : 0,
      "operationTime" : Timestamp(1746223914, 1),
      "code" : 2,
      "errmsg" : "Unknown projection operator y"
  }
  ```
+ MongoDB와 같은 플래너 버전 2.0에서는 프로젝션이 `$` 연산자 이후의 필드를 지원하지 않습니다.

  ```
  // Mongo and Planner Version 2 will error out
    db.col.find()
  { "_id" : ObjectId("68155fa812f843439b593f3f"), "x" : [ { "a" : 100 } ] }
   db.col.find({"x.a":100},{"x.$.a":1}) - // error
   
  // v1 will not error out 
   db.col.find()
  { "_id" : ObjectId("68155fa812f843439b593f3f"), "x" : [ { "a" : 100 } ] }
  db.col.find({"x.a":100},{"x.$.a":1})
  { "_id" : ObjectId("68155dee13b051d58239cd0a"), "x" : [ { "a" : 100 } ] }
  ```
+ MongoDB와 같은 플래너 버전 2.0에서는 `$hint`를 사용할 수 있습니다.

  ```
  // v1 will error out on $hint if there are no filters
  db.col.find({}).hint("x_1")
  Error: error: {
      "ok" : 0,
      "operationTime" : Timestamp(1746466616, 1),
      "code" : 2,
      "errmsg" : "Cannot use Hint for this Query. Index is multi key index , partial index or sparse index and query is not optimized to use this index."
  }
  
  
  // Mongo and Planner Version 2 will allow $hint usage
   db.col.find({}).hint("x_1")
  { "_id" : ObjectId("6818f790d5ba9359d68169cf"), "x" : 1 }
  ```