- MongoDB에서 Index의 대소문자는 엄격히 구분
- Document를 update할 때 해당 Index Key만 변경되지만 변경되는 Document 크기가 기존 Extent 공간 크기보다 큰 경우 더 큰 Extent 공간으로 마이그레이션 될 수 있기 때문에 성능 저하 현상이 발생 ( 설계 시 Extent 공간도 고려)
- Sort() / limit()은 함께 사용하는 것이 성능에 좋음
- Index를 활용하면 Sort된 형태로 반환되며 limit을 이용하면 불필요한 검색량을 줄여줄 수 있어서 효과로 예상
- reIndex는 기존 Index 제거 후 생성 됨
- B-Tree Index
- 인덱스를 생성 시, 인덱스는 해당 Field의 값을 가지고, Document들을 가르키는 포인터 값으로 이뤄진 B-Tree Index
- Field 값 + Document를 가르키는 포인터 값
- Collection 생성 시 _id 필드에 유니크 인덱스를 자동 생성(별도의 _id를 명시 하지 않는 것을 추천 / 내부 인덱스 생성)
- Cluster Index 개념이 존재하지 않기에 PK나 Secondary Index 나 내부 구조는 동일
- Index를 이용해 Document 검색할 때 Index -> Hiden Field(Record-Id) -> Data접근 하여 총 2번의 인덱스 검색
- Hiden Field로 생성되는 Record-Id 인덱스가 ClusterIndex 이지만 사용자는 이것을 생성하거나 사용할 수 없기 때문에 ClusterIndex는 없다고 봐야 한다.
- 인덱스 생성 시 서브Document 를 이용하여 생성은 가능하지만, 인덱스는 압축을 하지 않기에 자칫 인덱스 사이즈가 커지므로 인덱스로써 역효과를 가져올 수 있음
- WT Cache 상태에서는 데이터는 non압축 상태이지만, Index는 메모리 상 뿐만 아니라 디스크에도 prefix 압축된 상태로 사용(메모리의 효율성을 증대 가능)
- SubDocument 에 Index 생성 시 어떻게 find를 할 것인지 반드시 고민 후에 생성해야 하며 순서 또한 보장해야 함
- v4.2.2-3
- subdocument 내 모든 필드 내역을 find 조건에 작성 해야 하며
- 순서 또한 맞춰서 검색 조건에 포함
- Dot으로 검색 한다면, dot 으로 인덱스를 생성
- 서브 도큐먼트의 필드를 모두 가지고 순서가 같을 때만 인덱스 역활을 할 수 있음 (위와 동일)
- 필히 참고 : https://www.percona.com/blog/2020/07/24/mongodb-utilization-of-an-index-on-subdocuments/
- 인덱스도 prefix 압축 사용
- subdocument
- Equal 검색 및 앞 부분 일치할 때만 사용 가능하고, 부등호(부정) 에 비교에서는 사용 불가, 필드값 변형이 일어난 것, 함수 적용 등은 사용 못함(rdbms와 동일)
[ 가이드 ]
- Equal 검색을 지향합니다.
- 조건에 많이 사용하는 Field 쿼리에 대해서 선행 Filed 로 하여 Index 생성
- Cardinality 가 좋은 Field 에 대해서 Index 를 생성
- 날짜 검색을 해야 한다면, 가급적이면 _id 를 이용한 Range(날짜 지정 범위-$gte and $lte ) 검색을 지향
- 추가로 별도의 index 생성 또는 필드 생성에 대한 고민 (_id 로 대체 가능)
- Index 도 Disk Size 가 할당되며, 해당 Field 에 대해 수정이 발생 시 마다 변경 되기에 무분별한 Index 생성 및 Size가 큰 Field 에 대한 생성은 지양
- 검색하는 목적에 맞는 Index 의 Type을 지정 (특별히, Text 또는 지도 상의 거리 등)
- 서브 다큐먼트 Field에 대해서는 인덱스 생성을 지양(인덱스 사이즈가 작아야 성능에 효율)
- 2중 배열은 지양 . 필요 시 업데이트 검색 등이 힘듦 -> 체크해 보자
[createIndex]
db.collection.createIndex(keys, options)
Index Name |
Index Type |
Parameter |
Type |
Memo |
Non-Unique / Unique Index |
Option |
unique |
Bollean |
유일값 여부 {unique : true} |
Single Field / Compound Index |
|
|
|
단일 필드 또는 여러개의 필드를 이용하여 Index 를 생성 > Compound Index 생성 시 선행 필드가 중요하기에 Find / Update 진행 시 자주 사용하는 필드를 선행으로 지정 하면, 여러 쿼리에서 사용할 수 있기에 효율성이 증대 |
Multi Key Index |
|
|
|
배열에 지정된 내용을 인덱스 하기 위함 배열의 모든 요소에 대해 개별의 인덱스 객체들을 자동 생성 > 명시적으로 멀티키 타입을 지정할 필요 없음 |
Background Index (v4.2에서부터 해당 옵션은 사라지며, default 로 진행-index 생성 시 처음과 마지막에만 Lock) |
Option |
background |
Bollean |
Index 생성 시 많은 비용이 발생하여 성능 저하가 발생하는데, 적은 비용으로 백그라운드로 생성하여 DB에서 부하를 줄여 주는 방식 > 생성 진행되는 동안 background 로 생성하기에 메모리 체크가 필수 |
TTL Index |
Option |
expireAfterSeconds |
Integer |
|
Sparse Index |
Option |
sparse |
Bollean |
Field 에서 Null 값을 가진 데이터가 대부분이고 드물게 어떠한 값을 가지고 있는 경우 생성하면 효율적 (인덱스의 크기가 줄며, 효율성을 올릴 수 있음 -> Null 값을 제거하고 Index 생성) |
Partial Index (v3.2) |
Option |
partialFilterExpression |
Document |
Index 생성 시 해당 Field를 Filtering 한 결과를 생성 Ex ) 천만원 이상인 금액만 주로 Find하는 경우 인덱스 생성(해당 금액 이하는 Index 를 사용하지 못함) db.emp.createIndex({salary:1},{partialFilterExpression:{salary:{$gte:10000000}}}) |
GeoSpatial(2d) Index |
Option |
bits min max |
Integer number Number |
공간인덱스
지리 좌표 데이터의 효율적인 쿼리를 제공
|
GeoSpatial(2dsphere) Index |
Option |
2dsphereIndexVersion |
Integer |
지리 좌표 데이터의 효율적인 쿼리를 제공
|
GeoHayStack Index |
Option |
bucketSize |
Number |
|
Text Index |
Option
|
weights default_language Language_override textIndexVersion |
document String String Integer |
하나의 Collection에 하나의 Text Index만 생성 가능 |
Hashed Index |
|
|
|
|
Covered Index |
|
|
|
여러개의 Field로 생성된 Compound Index 에서 검색할 때 Index 검색 만으로도 조건을 만족하는 Document 를 추출이 가능한 경우 .explain() 확인 시 [...indexOnly:true]를 확인할 수 있음 |
Wildcard index (v4.2) |
|
wildcardProjection |
document |
https://docs.mongodb.com/manual/core/index-wildcard/#wildcard-index-core 아래 옵션은 사용 할 수 없음 * Compound * TTL * Text * 2d (Geospatial) * 2dsphere (Geospatial) * Hashed * Unique |
collation (v3.4) |
Option |
collation |
Document |
주로 강세등이 있는 언어들에 대해서 binary 화 한 후에 비교(French 등) * text indexes, * 2d indexes, and * geoHaystack indexes.
만약 collation option 없이 생성했다가 collation option 넣은 후에 동일하게 생성하려고 해도 생성이 안되며 기존 Index 삭제 후 재생성 해야함 |
[ Default Indexes : _id]
- Collection 생성 시, 별도로 생성하지 않는다면, 기본적으로 _id field에 대해서 Index가 생성
- unique Index이며 삭제할 수 없음
- PK나 Secondary index나 모두 내부는 동일하기에 Cluster index 개념이 없음
[ Single Field Indexes ]
- 1개의 필드로 생성된 것을 Single Field Indexes
- Index는 생성한 Field를 기준으로 정렬
[ Compound(Composite) Index ]
- 2개 이상의 필드가 연결된 것을 Compound Indexes
- 각각 다른 방식으로 정렬하여 생성 가능
[ Multikey Indexes ]
- document 내의 document 가 존재하는 embedded document 또는 array 형태의 Field에 Index를 생성
- Multikey Index 의 경우 shard key로 사용될 수 없음
- shard key는 하나의 chunk로 매핑되어야 하는데, 여러개의 엔트리가 들어 있는 형태로는 불가능
- Multi-key index는 커버링 인덱스 처리가 불가능
- 필드가 array인데 Index 생성하면 자동으로 multikey 인덱스로 생성
- Unique Multi-key index는 document 내에서 Unique 가 아닌 Collection 내에서 Unique 함
- Compound + Multikey Index에서는 하나의 Multikey 만 포함 가능
- 또한, 문제없이 compound + Multikey index로 생성되어 있는 경우 그 중 single field에 array 형태로 insert,update 를 시도하면 에러가 발생
ex 1) 아래와 같이 a,b 필드가 array 인 경우 {a:1, b:1} 이런식으로 2개의 compound multikey index를 생성할 수 없다.
{ _id: 1, a: [ 1, 2 ], b: [ 1, 2 ], category: "AB - both arrays" }
ex 2) {a:1, b:1} 이런 형태로 정상적으로 index가 문제 없이 생성되어 있는 collection 형태에서, 하나의 document에 a,b를 array 형태로 변경 시 문제 발생
{ _id: 1, a: [1, 2], b: 1, category: "A array" } <- b를 array 형태로 document 를 추가 수정 시 fail 발생
{ _id: 2, a: 1, b: [1, 2], category: "B array" } <- a를 array 형태로 document 를 추가 수정 시 fail 발생
ex3) compound + multikey index를 여러 array 에 사용하고 싶은 경우 아래와 같이 설계하면 사용 가능 { "a.x": 1, "a.z": 1 }
{ _id: 1, a: [ { x: 5, z: [ 1, 2 ] }, { z: [ 1, 2 ] } ] }
{ _id: 2, a: [ { x: 5 }, { z: 4 } ] }
[ Text Indexes ]
- 문자열 내용에 대한 텍스트 검색 쿼리를 지원
- 문자열 또는 문자열 요소의 배열인 모든 필드가 포함
- 하나의 Collection에 하나의 text index만 생성 가능
- 하나의 text index 생성 시 Compound로 생성 가능
- 생성하려는 Field에 text 로 명시 (다른 Index 생성과 다른 방식)
- text Index 생성하게 되면 기본적으로 해당 "field명_text" 명으로 생성
- $meta 를 이용하여 검색하는 text에 대해 가중치를 제공 가능
- mongodb에서 한글에 대해서 ngram, 형태소분석을 기본적으로 제공하지 않고 구분자 기반(공백문자) 기준으로 인덱싱 처리함
- 한 단어의 부분에 대해서도 검색을 가능하게 하려면 ngram full text index 기능을 사용해야함
- 참고 : https://sarc.io/index.php/nosql/1769-mongodb-text-index
- 구분자 기반(공백문자) 기준으로 인덱싱
# text Index 생성 방법
db.array.createIndex({"month_data":"text"})
# Compound 으로 생성 방법
db.reviews.createIndex(
{
subject: "text",
comments: "text"
}
)
#가중치 $meta 를 이용하여 sort 진행
db.array.find({$text:{$search:"서울"}},{score:{$meta: "textScore"}}).sort({score:{$meta:"textScore"}}).pretty()
#Wildcard Text Index
db.collection.createIndex( { "$**": "text" } )
- text Index를 여러개 생성 시 오류
- month_data 로 이미 생성 했는데, 추가로 생성 시 오류
- 가중치 추가하여 진행 ($meta)
- "아앙아" 라는 문자내에서 "아"를 검색하게 되면 가중치는 2가 됨 (아 *2개)
- > db.array.find({$text:{$search:"서울"}},{score:{$meta: "textScore"}}).sort({score:{$meta:"textScore"}}).pretty()
- 텍스트 내에 값을 찾으면 그 찾고자 하는 값의 개수에 곱하기가 되어 계산
- 참고 : https://sarc.io/index.php/nosql/1769-mongodb-text-index
[ Wildcard Indexes ]
- 필드 하위에 $**를 붙여서 이 필드의 하위 모든 문서에 와일드카드 익덱스를 만드는 것
- 필드 하위 필드들을 한번씩 Scan 각각의 인덱스를 만드는것
- 문서/배열로 재귀하여 모든 필드에 대한 값을 저장
- All fields on Index
- 각 Document에 대한 모든 Field 를 인덱싱
- _id 필드를 생략
- wildcardProjection
- wildcard 사용시 특정 필드 경로를 포함하거나 제외할 수 있는 옵션.
- 모든 색인을 작성하는 경우에만 유효
- Indexing은 추가로 발견되는 포함된 문서를 계속 탐색
#Wildcard Index / attributes 필드의 하위 document에 인덱스생성
db.collection.createIndex({ "attributes.$**": 1 })
# All fields on Index
db.collection.createIndex( { "$**" : 1 } )
#Wildcard Text Index
db.collection.createIndex( { "$**": "text" } )
[ 2dsphere Indexes ]
[ 2d Indexes ]
[ geoHaystack Indexes ]
[ Hashed Indexes ]
[ Index Properties ]
[ Index Builds on Populated Collections ]
[ Index Intersection ]
- 2개의 각기 다른 Field를 가진 Index들이 하나의 쿼리에 대해 인덱스를 이용(하나의 쿼리에 2개의 인덱스가 사용)
- Equal + Equal로 이루어진 쿼리 의 Index의 경우 AND_SORTED 스테이지가 사용
- Equal + Range로 이루어진 쿼리의 Index의 경우 AND_HASHED 스테이지가 사용
- Index Intersection이 다른 방법보다 효율적이거나 최신의 알고리즘이 아니기에, 효율적인 최적화가 아니다.
- (Index Intersection을 사용한다는 것은 Index가 잘못 설계[각 Filed마다 Single Filed로 인덱스가 여러개 생성] 되어 어쩔수 없이 사용되어지는 방법이기에 인덱스 설계를 다시 고민해야 한다)
- 인덱스 인터섹션 최적화가 사용되는 경우는 어떤 인덱스로도 최적화하기가 어렵다고 판단되는 경우 사용
[ Manage Indexes ]
[ Measure Index Use ]
[Indexing Strategies ]
[ Indexing Reference ]
[getIndexes()]
- Collection 의 Index 정보 가져오기 : db.collection.getIndexes()
- listIndexes 라는 권한이 필요 (read role 있으면 가능)
[ Index 사용통계 ]
- Index 사용 통계
- db.monsters.aggregate([{ $indexStats: {} }]).pretty()
- Ops : 0 이므로 한번도 _id 로 검색을 하지 않음
[ explain() ]
- Explain 확인
- executionStats 모드
- 인덱스 사용 여부
- 스캔한 문서들의 수
- 쿼리의 수행 시간
- allPlansExecution 모드
- 쿼리 계획을 선택하는데 필요한 부분적인 실행 통계
- 쿼리 계획을 선택하게 된 이유
[ Background Index 생성 ]
- MongoDB 인덱스를 생성하는 경우 (Foreground) Collection Lock 이 걸리게 된다.(쿼리 웨이팅 발생, 단 빠르게 생성) , (Session Blocking 발생-순간)
- 다만, Background Index로 생성하는 경우 Lock을 피할수 있기에 동시 사용성이 증가
- Background Index 생성 시 해당 collection으로 session유입 시 Index생성이 잠시 중단 되었다가 완료 되면 다시 시작 (Foreground Index보다 생성 시간이 늦어짐)
- Index 생성이 완료 되면 그 때 OpLog에 작성이 되며, 이 것을 받아 Secondary에서도 동일하게 Background로 시작(v2.4의 경우 Secondary에서는 Foreground로 생성 되는 버그. 주의)
- Collection의 Document가 많거나 Session 유입이 아주 많다면 세컨드리에서 포그라운드로 먼저 생성 후 프라이머리와 교체하는 것도 방법
- RDBMS의 경우 인덱스 생성 시 버퍼 공간을 사용하지만, 몽고 디비의 경우 따로 버퍼를 사용하지 않으며 트랜잭션로그(Undo Log)를 사용하지도 않기 때문에 오래 걸릴수도 있지만, 반대로 단순하기 때문에 버퍼 영역으로 인해 실패하거나 DB에 문제를 일으키지 않는 장점
- 인덱스 삭제의 경우도 메타 정보를 변경하고 인덱스와 연관된 데이터 파일만 삭제하면 되므로 매우 빠르게 진행(점검을 걸거나 할 필요 없음, 하지만 한순간 데이터베이스 잠금을 필요로 하므로 쿼리 처리량 낮은 시점에 삭제하는 것이 좋음)
- Background Index 생성 시, DB가 재시작(인덱스 빌드 프로세스를 강제 종료) 된다면 Index도 DB가 시작되면서 다시 시작하게 됨. 이 때 Foreground로 시작. 이 때 indexBulidRetry 옵션을 False로 설정하면 막을 수 있음
- 생성되는 지 체크하기 위해서 MongoDB Log나 OpLog를 통해 세컨더리에 생성 되었는지 확인 하면 됨
'MongoDB > MongoDB-Study_완료' 카테고리의 다른 글
[MongoDB] [Study11] 모델링 (0) | 2021.04.16 |
---|---|
[MongoDB] [Study-10] Lock & Transactions (0) | 2021.04.16 |
[MongoDB][Study-8] Aggregation (0) | 2021.04.16 |
[MongoDB][Study-7] Find / FindAndModify / Cursor (0) | 2021.03.28 |
[MongoDB] [Study-6] MongoDB CRUD 쓰기 연산 (0) | 2021.03.28 |