Azure Cosmos DB for MongoDB에서 인덱싱 관리

적용 대상: MongoDB

Azure Cosmos DB for MongoDB는 Azure Cosmos DB의 핵심 인덱스 관리 기능을 활용합니다. 이 문서에서는 Azure Cosmos DB for MongoDB를 사용하여 인덱스를 추가하는 방법을 중점적으로 설명합니다. 인덱스는 데이터를 대략적으로 더 빠르게 쿼리하는 특수한 데이터 구조입니다.

MongoDB 서버 버전 3.6 이상에 대한 인덱싱

Azure Cosmos DB for MongoDB 서버 버전 3.6 이상은 _id 필드 및 분할된 데이터베이스 키(분할된 컬렉션에서만)를 자동으로 인덱싱합니다. API는 분할된 키별 _id 필드의 고유성을 자동으로 적용합니다.

MongoDB용 API는 기본적으로 모든 필드를 인덱싱하는 Azure Cosmos DB for NoSQL과 다르게 동작합니다.

인덱싱 정책 편집

Azure Portal 내 데이터 탐색기에서 인덱싱 정책을 편집하는 것이 좋습니다. 데이터 탐색기의 인덱싱 정책 편집기에서 단일 필드 및 와일드카드 인덱스를 추가할 수 있습니다.

Indexing policy editor

참고 항목

데이터 탐색기에서 인덱싱 정책 편집기를 사용하여 복합 인덱스를 만들 수는 없습니다.

인덱스 형식

단일 필드

단일 필드에 인덱스를 만들 수 있습니다. 단일 필드 인덱스의 정렬 순서는 중요하지 않습니다. 다음 명령은 name 필드에 인덱스를 만듭니다.

db.coll.createIndex({name:1})

Azure Portal에서 name에 동일한 단일 필드 인덱스를 만들 수 있습니다.

Add name index in indexing policy editor

사용 가능한 경우 하나의 쿼리가 여러 개의 단일 필드 인덱스를 사용합니다. 컬렉션당 최대 500개의 단일 필드 인덱스를 만들 수 있습니다.

복합 인덱스(MongoDB 서버 버전 3.6 이상)

API for MongoDB에서 쿼리에 한 번씩 여러 필드를 정렬할 수 있는 기능이 필요한 경우 복합 인덱스가 필요합니다. 정렬할 필요가 없는 여러 필터가 포함된 쿼리의 경우 인덱싱 비용을 절약하기 위해 복합 인덱스 대신 단일 필드 인덱스를 여러 개 만듭니다.

복합 인덱스의 각 필드에 대한 복합 인덱스 또는 단일 필드 인덱스는 쿼리에서 필터링에 대한 동일한 성능을 생성합니다.

배열 관련 제한 사항으로 인해 중첩 필드의 복합 인덱스는 기본적으로 지원되지 않습니다. 중첩 필드에 배열이 포함되지 않은 경우 인덱스가 의도한 대로 작동합니다. 중첩 필드에 배열이 포함된 경우(경로의 아무 곳이나) 인덱스에서 해당 값이 무시됩니다.

예를 들어 경로에 배열이 없으므로 이 경우 people.dylan.age를 포함하는 복합 인덱스가 작동합니다.

{
  "people": {
    "dylan": {
      "name": "Dylan",
      "age": "25"
    },
    "reed": {
      "name": "Reed",
      "age": "30"
    }
  }
}

경로에 배열이 있으므로 이 경우 동일한 복합 인덱스가 작동하지 않습니다.

{
  "people": [
    {
      "name": "Dylan",
      "age": "25"
    },
    {
      "name": "Reed",
      "age": "30"
    }
  ]
}

이 기능은 ‘EnableUniqueCompoundNestedDocs’ 기능을 사용하도록 설정하여 데이터베이스 계정에 대해 사용하도록 설정할 수 있습니다.

참고 항목

배열에는 복합 인덱스를 만들 수 없습니다.

다음 명령은 nameage 필드에 복합 인덱스를 만듭니다.

db.coll.createIndex({name:1,age:1})

다음 예제와 같이 복합 인덱스를 사용하여 여러 필드에서 한 번에 효율적으로 정렬할 수 있습니다.

db.coll.find().sort({name:1,age:1})

또한 앞의 복합 인덱스를 사용하여 모든 필드에서 반대의 정렬 순서로 쿼리를 효율적으로 정렬할 수도 있습니다. 예를 들면 다음과 같습니다.

db.coll.find().sort({name:-1,age:-1})

그러나 복합 인덱스의 경로 시퀀스는 쿼리와 정확히 일치해야 합니다. 다음은 추가 복합 인덱스가 필요한 쿼리의 예입니다.

db.coll.find().sort({age:1,name:1})

Multikey 인덱스

Azure Cosmos DB는 배열에 저장된 콘텐츠를 인덱싱하기 위해 Multikey 인덱스를 만듭니다. 배열 값을 사용하여 필드를 인덱싱하는 경우 Azure Cosmos DB는 배열의 모든 요소를 자동으로 인덱싱합니다.

지리 공간적 인덱스

많은 지리 공간적 연산자가 지리 공간적 인덱스를 활용합니다. 현재 Azure Cosmos DB for MongoDB는 2dsphere 인덱스를 지원합니다. 이 API는 아직 2d 인덱스를 지원하지 않습니다.

location 필드에 지리 공간적 인덱스를 만드는 예는 다음과 같습니다.

db.coll.createIndex({ location : "2dsphere" })

텍스트 인덱스

현재 Azure Cosmos DB for MongoDB는 텍스트 인덱스를 지원하지 않습니다. 문자열에 대한 텍스트 검색 쿼리의 경우 Azure Cosmos DB와 통합된 Azure AI 검색을 사용해야 합니다.

와일드카드 인덱스

와일드카드 인덱스를 사용하면 알 수 없는 필드에 대해 쿼리를 지원할 수 있습니다. 패밀리에 대한 데이터를 보유하는 컬렉션이 있다고 가정해 보겠습니다.

다음은 해당 컬렉션의 예제 문서의 일부입니다.

"children": [
   {
     "firstName": "Henriette Thaulow",
     "grade": "5"
   }
]

아래는 또 다른 예이며 이번에는 children에서 약간 다른 속성 집합을 사용합니다.

"children": [
    {
     "familyName": "Merriam",
     "givenName": "Jesse",
     "pets": [
         { "givenName": "Goofy" },
         { "givenName": "Shadow" }
         ]
   },
   {
     "familyName": "Merriam",
     "givenName": "John",
   }
]

이 컬렉션에서 문서에는 여러 가지 사용 가능한 속성이 포함될 수 있습니다. children 배열의 모든 데이터를 인덱싱하려는 경우 두 가지 옵션이 있습니다. 각 개별 속성에 대해 별도의 인덱스를 만드는 옵션과 전체 children 배열에 대해 하나의 와일드카드 인덱스를 만드는 옵션입니다.

와일드카드 인덱스 만들기

다음 명령은 children 내의 모든 속성에 와일드카드 인덱스를 만듭니다.

db.coll.createIndex({"children.$**" : 1})

MongoDB와 달리 와일드카드 인덱스는 쿼리 조건자의 여러 필드를 지원할 수 있습니다. 각 속성에 대한 별도의 인덱스를 만드는 대신 하나의 와일드카드 인덱스를 사용해도 쿼리 성능에 차이가 없습니다.

와일드카드 구문을 사용하여 다음과 같은 인덱스 유형을 만들 수 있습니다.

  • 단일 필드
  • 지리 공간적

모든 속성 인덱싱

모든 필드에 와일드카드 인덱스를 만드는 방법은 다음과 같습니다.

db.coll.createIndex( { "$**" : 1 } )

Azure Portal에서 데이터 탐색기를 사용하여 와일드카드 인덱스를 만들 수도 있습니다.

Add wildcard index in indexing policy editor

참고 항목

개발을 이제 막 시작하는 경우 모든 필드에서 와일드카드 인덱스를 사용하여 시작하는 것이 가장 좋습니다. 이를 통해 개발을 간소화하고 쿼리를 보다 쉽게 최적화할 수 있습니다.

많은 필드가 있는 문서는 쓰기 및 업데이트에 대한 높은 RU(요청 단위) 요금이 부과될 수 있습니다. 따라서 쓰기 작업이 많은 경우에는 와일드카드 인덱스를 사용하는 대신 개별적으로 경로를 인덱싱해야 합니다.

참고 항목

데이터가 있는 기존 컬렉션의 고유 인덱스 지원은 미리 보기에서 사용할 수 있습니다. 이 기능은 'EnableUniqueIndexReIndex' 기능을 사용하도록 설정하여 데이터베이스 계정에 대해 사용하도록 설정할 수 있습니다.

제한 사항

와일드카드 인덱스는 다음 인덱스 유형 또는 속성을 지원하지 않습니다.

  • 복합
  • TTL
  • 고유한

MongoDB와 달리 Azure Cosmos DB for MongoDB에는 다음에 대한 와일드카드 인덱스를 사용할 수 없습니다.

  • 여러 특정 필드를 포함하는 와일드카드 인덱스 만들기

    db.coll.createIndex(
        { "$**" : 1 },
        { "wildcardProjection " :
            {
               "children.givenName" : 1,
               "children.grade" : 1
            }
        }
    )
    
  • 여러 특정 필드를 제외하는 와일드카드 인덱스 만들기

    db.coll.createIndex(
        { "$**" : 1 },
        { "wildcardProjection" :
            {
               "children.givenName" : 0,
               "children.grade" : 0
            }
        }
    )
    

또는 여러 와일드카드 인덱스를 만들 수 있습니다.

인덱스 속성

다음 작업은 유선 프로토콜 버전 4.0을 지원하는 계정 및 그 이전 버전을 지원하는 계정에서 일반적입니다. 지원되는 인덱스 및 인덱싱된 속성에 대해 자세히 알아볼 수 있습니다.

고유 인덱스

고유 인덱스는 두 개 이상의 문서에서 인덱싱된 필드에 대해 동일한 값을 포함하지 않도록 하는 데 유용합니다.

다음 명령은 student_id 필드에 고유 인덱스를 만듭니다.

globaldb:PRIMARY> db.coll.createIndex( { "student_id" : 1 }, {unique:true} )
{
    "_t" : "CreateIndexesResponse",
    "ok" : 1,
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 4
}

분할된 컬렉션의 경우 고유 인덱스를 만들려면 분할(파티션) 키를 제공해야 합니다. 즉, 분할된 컬렉션의 모든 고유 인덱스는 필드 중 하나가 분할 키인 복합 인덱스입니다. 주문의 첫 번째 필드는 분할 키여야 합니다.

다음 명령은 student_iduniversity 필드에서 고유 인덱스를 사용하여 분할된 컬렉션 coll(분할 키는 university)을 만듭니다.

globaldb:PRIMARY> db.runCommand({shardCollection: db.coll._fullName, key: { university: "hashed"}});
{
    "_t" : "ShardCollectionResponse",
    "ok" : 1,
    "collectionsharded" : "test.coll"
}
globaldb:PRIMARY> db.coll.createIndex( { "university" : 1, "student_id" : 1 }, {unique:true});
{
    "_t" : "CreateIndexesResponse",
    "ok" : 1,
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 3,
    "numIndexesAfter" : 4
}

앞의 예제에서 "university":1 절을 생략하면 다음 메시지와 함께 오류가 반환됩니다.

cannot create unique index over {student_id : 1.0} with shard key pattern { university : 1.0 }

제한 사항

컬렉션이 비어 있는 동안 고유 인덱스를 만들어야 합니다.

배열 관련 제한 사항으로 인해 중첩 필드의 고유 인덱스는 기본적으로 지원되지 않습니다. 중첩 필드에 배열이 포함되지 않은 경우 인덱스가 의도한 대로 작동합니다. 중첩 필드에 배열이 포함된 경우(경로의 아무 곳이나) 고유 인덱스에서 해당 값이 무시되고 해당 값에 대한 고유성은 유지되지 않습니다.

예를 들어, 경로에 배열이 없으므로 이 경우 people.tom.age의 고유 인덱스가 작동합니다.

{ "people": { "tom": { "age": "25" }, "mark": { "age": "30" } } }

하지만 이 경우에는 경로에 배열이 있으므로 작동하지 않습니다.

{ "people": { "tom": [ { "age": "25" } ], "mark": [ { "age": "30" } ] } }

이 기능은 ‘EnableUniqueCompoundNestedDocs’ 기능을 사용하도록 설정하여 데이터베이스 계정에 대해 사용하도록 설정할 수 있습니다.

TTL 인덱스

특정 컬렉션에서 문서 만료를 사용하려면 TTL(Time to Live) 인덱스를 만들어야 합니다. TTL 인덱스는 _ts 필드에 expireAfterSeconds 값을 사용한 인덱스입니다.

예시:

globaldb:PRIMARY> db.coll.createIndex({"_ts":1}, {expireAfterSeconds: 10})

위의 명령은 마지막 10초에서 수정되지 않은 db.coll 컬렉션의 문서를 삭제합니다.

참고 항목

_ts 필드는 Azure Cosmos DB 전용이며 MongoDB 클라이언트에서 액세스할 수 없습니다. 문서의 마지막 수정에 대한 타임스탬프가 포함된 예약된(시스템) 속성입니다.

인덱스 진행률 추적

Azure Cosmos DB for MongoDB 버전 3.6 이상에서는 데이터베이스 인스턴스의 인덱스 진행률을 추적하는 currentOp() 명령을 지원합니다. 이 명령은 데이터베이스 인스턴스에서 진행 중인 작업에 대한 정보가 포함된 문서를 반환합니다. currentOp 명령을 사용하여 원시 MongoDB의 모든 진행 중인 작업을 추적할 수 있습니다. Azure Cosmos DB for MongoDB에서 이 명령은 인덱스 작업 추적만 지원합니다.

다음은 currentOp 명령을 사용하여 인덱스 진행률을 추적하는 방법을 보여주는 몇 가지 예입니다.

  • 컬렉션에 대한 인덱스 진행률 가져오기:

    db.currentOp({"command.createIndexes": <collectionName>, "command.$db": <databaseName>})
    
  • 데이터베이스의 모든 컬렉션에 대한 인덱스 진행률 가져오기:

    db.currentOp({"command.$db": <databaseName>})
    
  • Azure Cosmos DB 계정의 모든 데이터베이스 및 컬렉션에 대한 인덱스 진행률 가져오기:

    db.currentOp({"command.createIndexes": { $exists : true } })
    

인덱스 진행률 출력의 예

인덱스 진행률 세부 정보에는 현재 인덱스 작업에 대한 진행률이 표시됩니다. 다음은 인덱스 진행률의 여러 단계에 대한 출력 문서 형식을 보여주는 예제입니다.

  • "foo" 컬렉션과 "bar" 데이터베이스의 인덱스 작업(60% 완료)은 다음과 같은 출력 문서를 갖게 됩니다. Inprog[0].progress.total 필드는 목표 완료 백분율로 100을 표시합니다.

    {
          "inprog" : [
          {
                  ………………...
                  "command" : {
                          "createIndexes" : foo
                          "indexes" :[ ],
                          "$db" : bar
                  },
                  "msg" : "Index Build (background) Index Build (background): 60 %",
                  "progress" : {
                          "done" : 60,
                          "total" : 100
                  },
                  …………..…..
          }
          ],
          "ok" : 1
    }
    
  • "foo" 컬렉션과 "bar" 데이터베이스에서 인덱스 작업을 막 시작한 경우에는 측정 가능한 수준에 도달할 때까지 출력 문서의 진행률이 0%로 표시될 수 있습니다.

    {
          "inprog" : [
          {
                  ………………...
                  "command" : {
                          "createIndexes" : foo
                          "indexes" :[ ],
                          "$db" : bar
                  },
                  "msg" : "Index Build (background) Index Build (background): 0 %",
                  "progress" : {
                          "done" : 0,
                          "total" : 100
                  },
                  …………..…..
          }
          ],
         "ok" : 1
    }
    
  • 진행 중인 인덱스 작업이 완료되면 출력 문서에 빈 inprog 작업이 표시됩니다.

    {
        "inprog" : [],
        "ok" : 1
    }
    

백그라운드 인덱스 업데이트

백그라운드 인덱스 속성에 지정된 값에 관계 없이 인덱스 업데이트는 항상 백그라운드에서 수행됩니다. 인덱스 업데이트는 다른 데이터베이스 작업 보다 낮은 우선 순위로 RU(요청 단위)를 사용하므로 인덱스를 변경해도 쓰기, 업데이트 또는 삭제에 대한 가동 중지 시간이 발생하지 않습니다.

새 인덱스를 추가하는 경우 읽기 가용성에는 영향을 주지 않습니다. 인덱스 변환이 완료되면 쿼리에서 새 인덱스만 활용합니다. 인덱스를 변환하는 동안 쿼리 엔진은 기존 인덱스를 계속 사용하므로 인덱싱 변경을 시작하기 전에 관찰한 내용에 대한 인덱싱 변환 중에 유사한 읽기 성능을 확인할 수 있습니다. 새 인덱스를 추가하는 경우 쿼리 결과가 불완전하거나 일치하지 않을 위험도 없습니다.

인덱스를 제거하고 삭제된 인덱스에 대한 필터가 있는 쿼리를 바로 실행하는 경우 인덱스 변환이 완료될 때까지 결과가 일관적이고 완전하지 않을 수 있습니다. 인덱스를 제거하는 경우 새로 제거된 이러한 인덱스에서 쿼리가 필터링하면 쿼리 엔진에서 일관되거나 완전한 결과를 제공하지 않습니다. 대부분의 개발자는 인덱스를 삭제하지 않고 즉시 쿼리를 시도하므로 실제로는 이러한 상황이 발생할 가능성이 낮습니다.

참고 항목

인덱스 진행률을 추적할 수 있습니다.

ReIndex 명령

reIndex 명령은 컬렉션의 모든 인덱스를 다시 만듭니다. 드문 경우로 쿼리 성능 또는 컬렉션의 다른 인덱스 문제는 reIndex 명령을 실행하여 해결할 수 있습니다. 인덱싱에 문제가 있는 경우 reIndex 명령으로 인덱스를 다시 생성하는 것이 좋습니다.

다음 구문을 사용하여 reIndex 명령을 실행할 수 있습니다.

db.runCommand({ reIndex: <collection> })

아래 구문을 사용하여 reIndex 명령을 실행하면 컬렉션에서 쿼리 성능이 향상되는지 확인할 수 있습니다.

db.runCommand({"customAction":"GetCollection",collection:<collection>, showIndexes:true})

샘플 출력:

{
        "database" : "myDB",
        "collection" : "myCollection",
        "provisionedThroughput" : 400,
        "indexes" : [
                {
                        "v" : 1,
                        "key" : {
                                "_id" : 1
                        },
                        "name" : "_id_",
                        "ns" : "myDB.myCollection",
                        "requiresReIndex" : true
                },
                {
                        "v" : 1,
                        "key" : {
                                "b.$**" : 1
                        },
                        "name" : "b.$**_1",
                        "ns" : "myDB.myCollection",
                        "requiresReIndex" : true
                }
        ],
        "ok" : 1
}

reIndex가 쿼리 성능을 향상시키는 경우 requiresReIndex는 true가 됩니다. reIndex가 쿼리 성능을 향상시키지 않는 경우 이 속성은 생략됩니다.

인덱스를 사용하여 컬렉션 마이그레이션

현재는 컬렉션에 문서가 포함되지 않은 경우에만 고유 인덱스를 만들 수 있습니다. 많이 사용되는 MongoDB 마이그레이션 도구는 데이터를 가져온 후 고유 인덱스를 만들도록 시도합니다. 이 문제를 피하려면 마이그레이션 도구를 사용할 수 있도록 하는 대신 해당 컬렉션 및 고유 인덱스를 수동으로 만들 수 있습니다. 명령줄에서 --noIndexRestore 플래그를 사용하여 mongorestore에 대해 이 동작을 수행할 수 있습니다.

MongoDB 버전 3.2에 대한 인덱싱

사용 가능한 인덱싱 기능 및 기본값은 MongoDB 유선 프로토콜의 버전 3.2와 호환되는 Azure Cosmos DB 계정에서 다릅니다. 계정의 버전을 확인하고 버전 3.6으로 업그레이드할 수 있습니다.

버전 3.2를 사용하는 경우 이 섹션에서는 버전 3.6 이상과의 주요 차이점을 간략하게 설명합니다.

기본 인덱스 삭제(버전 3.2)

Azure Cosmos DB for MongoDB 버전 3.6 이상과 달리 버전 3.2는 기본적으로 모든 속성을 인덱싱합니다. 다음 명령을 사용하여 컬렉션(coll)에 대한 이러한 기본 인덱스를 삭제할 수 있습니다.

> db.coll.dropIndexes()
{ "_t" : "DropIndexesResponse", "ok" : 1, "nIndexesWas" : 3 }

기본 인덱스를 삭제한 후에는 버전 3.6 이상에서와 같이 더 많은 인덱스를 추가할 수 있습니다.

복합 인덱스(버전 3.2)

복합 인덱스는 문서의 여러 필드에 대한 참조를 유지합니다. 복합 인덱스를 만들려는 경우 버전 3.6 또는 4.0으로 업그레이드합니다.

와일드카드 인덱스(버전 3.2)

와일드카드 인덱스를 만들려는 경우 버전 4.0 또는 3.6으로 업그레이드합니다.

다음 단계