Indexes
이 페이지의 내용
개요
이 가이드에서는 MongoDB Kotlin 드라이버를 사용하여 인덱스 를 생성하고 managed 방법에 대해 설명합니다.
인덱스는 MongoDB에서 쿼리를 효율적으로 실행할 수 있도록 지원합니다. 인덱스가 없으면 MongoDB는 각 쿼리와 일치하는 문서를 찾기 위해 collection의 모든 문서를 스캔( collection 스캔)해야 합니다. 이러한 collection 스캔은 속도가 느리고 애플리케이션 성능에 부정적인 영향을 미칠 수 있습니다. 쿼리에 적합한 인덱스가 있는 경우 MongoDB는 인덱스를 사용하여 쿼리가 검사해야 하는 문서를 제한할 수 있습니다.
인덱스에는 다음과 같은 이점도 있습니다.
인덱스를 사용하면 효율적으로 정렬할 수 있습니다.
인덱스를 사용하면 지리 공간적 쿼리와 같은 특수 기능을 사용할 수 있습니다.
인덱스를 사용하면 필드 값이 고유하도록 제약 조건을 만들 수 있습니다.
학습 내용은 서버 매뉴얼의 인덱스 를 참조하세요.
팁
업데이트 작업은 업데이트할 문서를 찾을 때 인덱스를 사용하고, 삭제 작업은 삭제할 문서를 찾을 때 인덱스를 사용합니다. 집계 파이프라인의 특정 단계 에서도 인덱스를 사용하여 성능을 개선합니다.
쿼리 커버리지 및 성능
MongoDB에 대해 쿼리를 실행할 때 명령에 다양한 요소가 포함될 수 있습니다.
찾고 있는 필드와 값을 지정하는 쿼리 기준
읽기 고려 (read concern)와 같이 쿼리 실행에 영향을 미치는 옵션
MongoDB가 반환하는 필드를 지정하기 위한 프로젝션 기준(선택 사항)
MongoDB에서 반환되는 문서의 순서를 지정하는 정렬 기준(선택 사항)
쿼리, 프로젝션, 정렬에 지정된 모든 필드가 동일한 인덱스에 있는 경우 MongoDB는 인덱스에서 직접 결과를 반환하며, 이를 커버 쿼리라고도 합니다.
중요
정렬 순서
정렬 기준은 인덱스의 순서와 일치하거나 반대가 되어야 합니다.
name
필드의 인덱스를 오름차순 (A-Z) 으로 age
인덱스를 내림차순 (9-0) 으로 가정해 보겠습니다.
name_1_age_-1
MongoDB는 다음 중 한 가지 방법으로 데이터를 정렬할 때 이 인덱스를 사용합니다.
name
오름차순,age
내림차순name
내림차순,age
오름차순
name
및 age에 오름차순 정렬을 지정하거나 name 및 age
에 내림차순 정렬을 지정하려면 인메모리 정렬을 수행해야 합니다.
인덱스가 쿼리 기준 및 프로젝션을 포함하는지 확인하는 방법에 대한 자세한 내용은 쿼리 커버리지에 대한 MongoDB Server 매뉴얼 문서를 참조하세요.
운영 고려 사항
다음 지침에서는 애플리케이션에서 인덱스를 사용하는 방식을 최적화하는 방법에 대해 설명합니다.
쿼리 성능을 향상시키려면 애플리케이션의 쿼리와 정렬된 결과를 반환하는 작업에 자주 나타나는 필드에 인덱스를 빌드합니다.
추가하는 각 인덱스는 활성화되면 디스크 공간과 메모리를 사용하므로 용량 계획을 위해 인덱스 메모리와 디스크 사용량을 추적합니다.
자주 사용하지 않는 인덱스는 추가하지 마세요. 쓰기 작업이 인덱스된 필드를 업데이트하면 MongoDB는 관련 인덱스를 업데이트합니다.
MongoDB는 동적 스키마를 지원하므로 애플리케이션은 이름을 미리 알 수 없거나 임의적인 필드를 쿼리할 수 있습니다. MongoDB 4.2는 이러한 쿼리를 지원하기 위해 와일드카드 인덱스를 도입했습니다. 와일드카드 인덱스는 워크로드 기반 인덱스 계획을 대체하도록 설계되지 않았습니다.
데이터 모델을 설계하고 애플리케이션에 적합한 인덱스를 선택하는 방법에 대한 자세한 내용은 인덱싱 전략 및 데이터 모델링 및 인덱스에 대한 MongoDB 서버 설명서를 참조하세요.
인덱스 유형
MongoDB는 데이터 쿼리를 지원하기 위해 여러 가지 인덱스 유형을 지원합니다. 다음 섹션에서는 가장 일반적인 인덱스 유형을 설명하고 각 인덱스 유형을 생성하기 위한 샘플 코드를 제공합니다. 인덱스 유형의 전체 목록은 MongoDB Server 매뉴얼의 인덱스 를 참조하세요.
팁
Kotlin 드라이버는 다음을 제공합니다. 클래스를 사용하여 인덱스를 생성하고 관리합니다. 이 클래스에는 다양한 MongoDB 인덱스 키 유형에 대한 인덱스 사양 문서를 생성하는 정적 팩토리 메서드가 포함되어 있습니다.
다음 예제에서는 createIndex() 메서드를 사용하여 다양한 인덱스를 생성하고 다음 데이터 클래스를 사용하여 MongoDB에서 데이터를 모델링할 수 있습니다.
// Data class for the movies collection data class Movie( val title: String, val year: Int, val cast: List<String>, val genres: List<String>, val type: String, val rated: String, val plot: String, val fullplot: String, ) // Data class for the theaters collection data class Theater( val theaterId: Int, val location: Location ) { data class Location( val address: Address, val geo: Point ) { data class Address( val street1: String, val city: String, val state: String, val zipcode: String ) } }
단일 필드 및 복합 인덱스
단일 필드 인덱스
단일 필드 인덱스는 컬렉션 문서 내의 단일 필드에 대한 참조가 있는 인덱스입니다. 단일 필드 쿼리 및 정렬 성능을 향상시키고, 특정 시간 후 또는 특정 클록 시간에 컬렉션에서 문서를 자동으로 제거하는 TTL 인덱스 를 지원합니다.
참고
_id_
인덱스는 단일 필드 인덱스의 예입니다. 이 인덱스는 새 컬렉션이 생성될 때 _id
필드에 자동으로 생성됩니다.
다은 title
필드에 오름차순으로 인덱스를 생성하는 예입니다.
val resultCreateIndex = moviesCollection.createIndex(Indexes.ascending(Movie::title.name)) println("Index created: $resultCreateIndex")
Index created: title_1
다음은 앞에 설명한 코드 스니펫에서 생성된 인덱스로 처리되는 쿼리의 예입니다.
val filter = Filters.eq(Movie::title.name, "The Dark Knight") val sort = Sorts.ascending(Movie::title.name) val projection = Projections.fields( Projections.include(Movie::title.name), Projections.excludeId() ) data class Results(val title: String) val resultsFlow = moviesCollection.find<Results>(filter).sort(sort).projection(projection) resultsFlow.collect { println(it) }
자세한 내용은 단일 필드 인덱스 에 대한 MongoDB 서버 매뉴얼 섹션을 참조하세요.
복합 인덱스
복합 인덱스에는 컬렉션의 문서 내에 있는 여러 필드에 대한 참조가 포함되어 있어 쿼리 및 정렬 성능을 향상시킵니다.
팁
복합 인덱스, 인덱스 접두사 및 정렬 순서에 대한 자세한 내용은 여기를 참조하세요.
다음 예에서는 type
및 rated
필드에 복합 인덱스를 만듭니다.
val resultCreateIndex = moviesCollection.createIndex(Indexes.ascending(Movie::type.name, Movie::rated.name)) println("Index created: $resultCreateIndex")
Index created: type_1_rated_1
다음은 앞에 설명한 코드 스니펫에서 생성된 인덱스로 처리되는 쿼리의 예입니다.
val filter = Filters.and( Filters.eq(Movie::type.name, "movie"), Filters.eq(Movie::rated.name, "G") ) val sort = Sorts.ascending(Movie::type.name, Movie::rated.name) val projection = Projections.fields( Projections.include(Movie::type.name, Movie::rated.name), Projections.excludeId() ) val resultsFlow = moviesCollection.find(filter).sort(sort).projection(projection) resultsFlow.collect { println(it) }
자세한 내용은 복합 인덱스 에 대한 MongoDB 서버 매뉴얼 섹션을 참조하세요.
다중 키 인덱스(배열 필드의 인덱스)
멀티키 인덱스는 배열 값을 포함하는 인덱스로 필드를 지정하는 쿼리의 성능을 개선하는 인덱스입니다. 단일 필드 또는 복합 인덱스와 동일한 구문을 사용하여 멀티키 인덱스를 정의할 수 있습니다.
다음 예시에서는 rated
, genres
(문자열 배열) 및 title
필드에 복합 멀티 키 인덱스를 생성합니다.
val resultCreateIndex = moviesCollection.createIndex(Indexes.ascending(Movie::rated.name, Movie::genres.name, Movie::title.name)) println("Index created: $resultCreateIndex")
Index created: rated_1_genres_1_title_1
다음은 앞에 설명한 코드 스니펫에서 생성된 인덱스로 처리되는 쿼리의 예입니다.
val filter = Filters.and( Filters.eq(Movie::genres.name, "Animation"), Filters.eq(Movie::rated.name, "G") ) val sort = Sorts.ascending(Movie::title.name) val projection = Projections.fields( Projections.include(Movie::title.name, Movie::rated.name), Projections.excludeId() ) val resultsFlow = moviesCollection.find(filter).sort(sort).projection(projection) resultsFlow.collect { println(it) }
멀티키 인덱스는 쿼리 커버리지, 인덱스 바운드 계산 및 정렬 동작 측면에서 다른 인덱스와 다르게 작동합니다. 멀티키 인덱스의 동작과 제한 사항에 대한 논의를 포함하여 멀티키 인덱스에 대해 자세히 알아보려면 MongoDB Server 매뉴얼에서 멀티키 인덱스 를 참조하세요.
Atlas Search 및 Vector Search 인덱스
코틀린 (Kotlin) 운전자 를 사용하여 Atlas Search 및 Atlas Vector Search 인덱스를 프로그래밍 방식으로 관리 수 있습니다.
Atlas Search 기능을 사용하면 MongoDB Atlas에서 호스팅되는 컬렉션에서 전체 텍스트 검색을 수행할 수 있습니다. MongoDB Atlas Search에 대해 자세히 학습하려면 Atlas Search Indexes 문서를 참조합니다.
Atlas Vector Search 를 사용하면 MongoDB Atlas 에 저장된 벡터 임베딩에 대해 시맨틱 검색을 수행할 수 있습니다. Atlas Vector Search 에 학습 보려면 애그리게이션 빌더 가이드 의 Atlas Vector Search 섹션을 참조하세요.
컬렉션 에서 다음 메서드를 호출하여 Atlas Search 및 Vector Search 인덱스를 관리 있습니다.
createSearchIndex()
(검색 인덱스에만 유효)createSearchIndexes()
listSearchIndexes()
updateSearchIndex()
dropSearchIndex()
참고
Atlas Search 인덱스 관리 메서드는 비동기적으로 실행됩니다. 드라이버 메서드는 성공적으로 실행되었는지 확인하기 전에 반환될 수 있습니다. 인덱스의 현재 상태를 확인하려면 listSearchIndexes()
메서드를 호출합니다.
다음 섹션에서는 코드 예시를 제공하여 이전의 각 메서드를 사용하는 방법을 보여줍니다.
검색 인덱스 만들기
createSearchIndex() 메서드를 사용하여 단일 Atlas Search 인덱스 를 생성합니다. 이 메서드로는 Vector Search 인덱스 를 만들 수 없습니다 .
createSearchIndexes() 메서드를 사용하여 여러 개의 Atlas Search 또는 Vector Search 인덱스를 생성합니다.SearchIndexModel 을 생성해야 합니다. 각 인덱스 에 대해 인스턴스 를 생성한 SearchIndexModel
다음 인스턴스 목록을 createSearchIndexes()
메서드에 전달합니다.
다음 코드 예시에서는 Atlas Search 인덱스를 생성하는 방법을 보여줍니다.
val searchIdx = Document( "mappings", Document("dynamic", true) ) val resultCreateIndex = moviesCollection.createSearchIndex("myIndex", searchIdx)
여러 검색 또는 벡터 검색 인덱스를 만들려면 SearchIndexModel 을 만들어야 합니다. 각 인덱스 에 대한 인스턴스 입니다.
다음 코드 예시 에서는 한 번의 호출로 검색 및 벡터 검색 인덱스를 생성하는 방법을 보여줍니다.
val searchIdxMdl = SearchIndexModel( "searchIdx", Document("analyzer", "lucene.standard").append( "mappings", Document("dynamic", true) ), SearchIndexType.search() ) val vectorSearchIdxMdl = SearchIndexModel( "vsIdx", Document( "fields", listOf( Document("type", "vector") .append("path", "embeddings") .append("numDimensions", 1536) .append("similarity", "dotProduct") ) ), SearchIndexType.vectorSearch() ) val resultCreateIndexes = moviesCollection.createSearchIndexes( listOf(searchIdxMdl, vectorSearchIdxMdl) )
검색 인덱스 나열
listSearchIndexes() 메서드를 사용하여 컬렉션의 Atlas Search 인덱스 목록을 반환합니다.
다음 코드 예시에서는 collection의 검색 인덱스 목록을 인쇄하는 방법을 보여줍니다.
val searchIndexesList = moviesCollection.listSearchIndexes().toList()
검색 인덱스 업데이트
updateSearchIndex() 메서드를 사용하여 Atlas Search 인덱스를 업데이트할 수 있습니다.
다음 코드에서는 검색 업인덱스를데이트하는 방법을 보여줍니다.
moviesCollection.updateSearchIndex( "myIndex", Document("analyzer", "lucene.simple").append( "mappings", Document("dynamic", false) .append( "fields", Document( "title", Document("type", "string") ) ) ) )
검색 인덱스 제거
dropSearchIndex() 메서드를 사용하여 Atlas Search 인덱스를 제거할 수 있습니다.
다음 코드에서는 컬렉션에서 검색 인덱스를 삭제하는 방법을 보여줍니다.
moviesCollection.dropSearchIndex("myIndex");
Text Indexes
텍스트 인덱스 는 문자열 콘텐츠에 대한 텍스트 검색 쿼리를 지원합니다. 이러한 인덱스에는 값이 문자열 혹은 문자열 요소의 배열인 필드가 있을 수 있습니다. MongoDB는 다양한 언어에 대해 텍스트 검색을 지원합니다. 인덱스를 생성하는 경우 기본값 언어를 옵션으로 지정할 수 있습니다.
팁
MongoDB 는 향상된 전체 텍스트 검색 솔루션인 Atlas Search 를 제공합니다. Atlas Search 인덱스 및 사용 방법에 학습 보려면 이 가이드 의 Atlas Search 및 Vector Search 인덱스 섹션을 참조하세요.
단일 필드
다음 예시에서는 plot
필드에 텍스트 인덱스를 생성합니다.
try { val resultCreateIndex = moviesCollection.createIndex(Indexes.text(Movie::plot.name)) println("Index created: $resultCreateIndex") } catch (e: MongoCommandException) { if (e.errorCodeName == "IndexOptionsConflict") { println("there's an existing text index with different options") } }
Index created: plot_text
다음은 앞의 코드 스니펫에서 생성된 인덱스로 처리되는 쿼리의 예입니다. 텍스트 인덱스에는 정렬 순서가 포함되어 있지 않으므로 sort
가 생략되었습니다.
val filter = Filters.text("Batman") val projection = Projections.fields( Projections.include(Movie::fullplot.name), Projections.excludeId() ) data class Results(val fullplot: String) val resultsFlow = moviesCollection.find<Results>(filter).projection(projection) resultsFlow.collect { println(it) }
여러 필드
컬렉션에는 텍스트 인덱스 하나만 포함할 수 있습니다. 여러 텍스트 필드에 대해 텍스트 인덱스를 생성하려면 복합 인덱스를 생성해야 합니다. 텍스트 검색은 복합 인덱스 내의 텍스트 필드 모두에서 실행됩니다.
다음과 같은 스니펫은 title
및 genre
필드에 대한 복합 텍스트 인덱스를 생성합니다.
try { val resultCreateIndex = moviesCollection.createIndex( Indexes.compoundIndex( Indexes.text(Movie::title.name), Indexes.text(Movie::genres.name) ) ) println("Index created: $resultCreateIndex") } catch (e: MongoCommandException) { if (e.errorCodeName == "IndexOptionsConflict") { println("there's an existing text index with different options") } }
Index created: title_text_genre_text
자세한 내용은 Server Manual Entries를 참조합니다.
지리 공간적 인덱스
MongoDB는 2dsphere 인덱스 를 사용하여 지리 공간적 좌표 데이터 쿼리를 지원합니다. 2dsphere
인덱스를 사용하면 지리 공간적 데이터에 포함, 교차 및 근접성에 대해 쿼리할 수 있습니다. 지리 공간적 데이터 쿼리에 대한 자세한 내용은 MongoDB Server 매뉴얼의 지리 공간적 쿼리 를 참조하세요.
2dsphere
인덱스를 만들려면 GeoJSON 객체 만 포함하는 필드를 지정해야 합니다. 이 유형에 대해 자세히 알아보려면 MongoDB Server 매뉴얼에서 GeoJSON 객체 를 참조하세요.
sample_mflix
데이터베이스의 theaters
컬렉션에 있는 다음과 같은 샘플 문서의 location.geo
필드는 시어터의 좌표를 설명하는 GeoJSON Point 객체입니다.
{ "_id" : ObjectId("59a47286cfa9a3a73e51e75c"), "theaterId" : 104, "location" : { "address" : { "street1" : "5000 W 147th St", "city" : "Hawthorne", "state" : "CA", "zipcode" : "90250" }, "geo" : { "type" : "Point", "coordinates" : [ -118.36559, 33.897167 ] } } }
다음 예시에서는 location.geo
필드에 2dsphere
인덱스를 생성합니다.
val resultCreateIndex = theatersCollection.createIndex( Indexes.geo2dsphere("${Theater::location.name}.${Theater.Location::geo.name}") ) println("Index created: $resultCreateIndex")
Index created: location.geo_2dsphere
중요
이미 지리 공간적 인덱스로 포함된 필드에 지리 공간적 인덱스를 생성하려고 하면 오류가 발생합니다.
다음은 앞의 코드 스니펫에서 생성된 인덱스로 처리되는 지리 공간적 쿼리의 예입니다.
// MongoDB Headquarters in New York, NY. val refPoint = Point(Position(-73.98456, 40.7612)) val filter = Filters.near( "${Theater::location.name}.${Theater.Location::geo.name}", refPoint, 1000.0, 0.0 ) val resultsFlow = theatersCollection.find(filter) resultsFlow.collect { println(it) }
MongoDB 또한 2d
는 유클리드 평면에서 거리를 계산하고legacy coordinate pairs MongoDB 2.2 이전 버전에서 사용되는 " " 구문으로 작업하기 위한 인덱스를 지원합니다. 자세한 내용은 매뉴얼의 지리 공간적 쿼리 MongoDB Server 를 참조하세요.
Unique Indexes
고유 인덱스는 인덱스된 필드에 중복 값이 저장되는지 않도록 합니다. 디폴트로 MongoDB는 컬렉션 생성 시 _id
필드에 고유 인덱스를 생성합니다. 고유 인덱스를 생성하려면 중복을 방지하려는 필드 혹은 필드 조합을 지정하고 unique
옵션을 true
로 설정합니다.
다음 예시에서는 theaterId
필드에 고유한 내림차순 인덱스를 생성합니다.
try { val indexOptions = IndexOptions().unique(true) val resultCreateIndex = theatersCollection.createIndex( Indexes.descending(Theater::theaterId.name), indexOptions ) println("Index created: $resultCreateIndex") } catch (e: DuplicateKeyException) { println("duplicate field values encountered, couldn't create index: \t${e.message}") }
Index created: theaterId_-1
중요
고유 인덱스를 위반하는 중복 값을 저장하는 쓰기 작업을 수행하면 드라이버에서 DuplicateKeyException
오류가 발생하고 MongoDB에서 다음과 유사한 오류가 발생합니다.
E11000 duplicate key error index
자세한 내용은 MongoDB 서버 매뉴얼의 고유 인덱스 페이지 를 참조하세요.
클러스터화된 인덱스
Clustered indexes는 키 값을 기준으로 정렬된 문서를 저장하도록 컬렉션에 지시합니다. 클러스터형 인덱스를 생성하려면 컬렉션을 생성하는 경우 _id
필드를 키로 사용하고 고유 필드를 true
로 사용하여 클러스터형 인덱스 옵션을 지정합니다.
다음 예시에서는 vendors
collection의 _id
필드에 클러스터형 인덱스를 생성합니다.
val clusteredIndexOptions = ClusteredIndexOptions(Document("_id", 1), true) val createCollectionOptions = CreateCollectionOptions().clusteredIndexOptions(clusteredIndexOptions) database.createCollection("vendors", createCollectionOptions)
자세한 내용은 MongoDB Server 매뉴얼 섹션을 참조하세요.
인덱스 제거
_id
필드에서 기본값 고유 인덱스를 제외한 사용하지 않는 인덱스를 제거할 수 있습니다.
다음 섹션에서는 인덱스를 제거하는 방법에 대해 설명합니다.
인덱스 사양 문서 사용하기
인덱싱된 이름 필드 사용하기
와일드카드 문자를 사용하여 인덱스 모두 제거하기
인덱스 사양 문서를 사용하여 인덱스 제거
인덱스 사양 문서를 dropIndex()
메서드에 전달하여 컬렉션에서 인덱스를 제거합니다. 인덱스 사양 문서란 지정된 필드의 색인 유형을 지정하는 Bson
인스턴스를 말합니다.
다음 스니펫에서는 컬렉션의 title
필드에서 오름차순 인덱스를 제거합니다.
moviesCollection.dropIndex(Indexes.ascending(Movie::title.name));
중요
텍스트 인덱스를 삭제하려면 그 대신 인덱스 이름을 사용해야 합니다. 자세한 내용은 Remove an Index Using a Name Field 섹션을 참조합니다.
이름 필드를 사용하여 인덱스 제거
컬렉션에서 제거인덱스를하려면 인덱스의 name
필드를 dropIndex()
메서드에 전달합니다.
인덱스 이름을 찾아야 하는 경우 listIndexes()
메서드를 사용하여 인덱스에서 name
필드의 값을 확인합니다.
다음과 같은 스니펫은 컬렉션의 인덱스를 모두 검색하고 인쇄합니다.
val indexes = moviesCollection.listIndexes() indexes.collect { println(it.toJson()) }
텍스트 인덱스가 포함된 컬렉션에서 listIndex()
호출하는경우 출력은 다음과 같이 유사할 수 있습니다.
{ "v": 2, "key": {"_id": 1}, "name": "_id_" } { "v": 2, "key": {"_fts": "text", "_ftsx": 1}, "name": "title_text", "weights": {"title": 1}, "default_language": "english", "language_override": "language", "textIndexVersion": 3 }
이와 같은 출력은 기존 인덱스의 이름이 " _id " 및 " title_text " 임을 나타냅니다.
다음과 같은 스니펫은 컬렉션에서 "title_text" 인덱스를 제거합니다:
moviesCollection.dropIndex("title_text")
참고
복합 텍스트 인덱스에서 단일 필드를 제거할 수 없습니다. 인덱스된 필드를 업데이트하려면 인덱스를 전부 제거하고 새로운 인덱스를 생성해야 합니다.
와일드카드 문자를 사용하여 인덱스 제거
MongoDB 4.2부터 컬렉션에서 dropIndexes()
메서드를 호출하여 인댁스를 모두 제거할 수 있습니다.
moviesCollection.dropIndexes()
MongoDB 이전 버전의 경우 컬렉션의 dropIndex()
호출에 " * " 를 매개 변수로 전달합니다.
moviesCollection.dropIndex("*")
본 섹션의 메서드에 대한 자세한 내용은 다음 API 설명서를 참조합니다.