...
몽고디비 인덱스
DB에서 인덱스는 정말 중요한 역할을 합니다.
자주 조회되는 필드를 따로 저장해서 조회 밑 정렬 시의 속도를 빠르게 하는 기법입니다.
/* book 컬렉션의 someField 필드에 대해 인덱스를 블록킹 방식으로 생성한다.
명령 실행 후 인덱스 생성이 완료될 때까지 해당 컬렉션에 대한 모든 CRUD는 블록킹 된다. */
db.book.createIndex({name:1}) // name필드에 인덱스 설정
// single field index : 단일 key 인덱스, 1은 오름차순, -1은 내림차순
/* book 필드에 대해 인덱스를 논블록킹 방식으로 생성한다.
명령 실행 후 인덱스 생성이 진행 중이더라도 해당 컬렉션에 대한 모든 CRUD가 가능하다. */
db.someCollection.createIndex({name:1}, {background:1}) // 백그라운드 옵션
인덱스는 일반 필드 뿐만 아니라, 객체 값을 가지는 필드의 내부 속성에도 지정할 수 있습니다.
예를 들어 { name: { first: 'Zero', last: 'Cho' } } 가 있을 경우,
createIndex({ 'name.last': 1 }); 이렇게 인덱스 지정이 가능합니다.
참고로 _id 필드는 자동으로 인덱스 설정이 되어 있습니다.
웬만한 경우면 _id를 사용해서 조회하는 게 좋습니다.
복합 인덱스
또한 인덱스는 하나의 필드에만 지정할 필요는 없습니다.
여러 개의 필드를 묶어서 지정할 수도 있습니다.
// compound(복합) field index : 복합적으로 key index
db.book.createIndex({name:1, hits:1})
이 경우는 find할때 여러 필드를 검색할경우 더 빠르게 찾을 수 있도록 도와줍니다.
복합 인덱스는 순서가 중요합니다.
예를 들어, a, b, c 필드 순서로 인덱스를 설정한 경우, 자동으로 a와 a, b 필드에 대한 인덱스도 같이 생성됩니다.
위의 경우, name 필드만 조회하거나 name, hits 필드 두개를 조회할 때도 뒤의 인덱스를 사용할 수 있습니다.
하지만 hits 필드만 조회하거나 그외의 필드를 조회할 때는 인덱스를 사용할 수 없습니다.
텍스트 인덱스
인덱스를 지정할 때 text라고 넣어줍니다.
이 경우 $text 쿼리 연산자를 사용할 수 있습니다.
db.book.createIndex({name:"text"})
{ $text: { $search: 문자, $language: 언어, $caseSensitive: 대소문자구별 } }
문자열 필드의 인덱스 설계 전략
- String 타입의 필드 값에 대해 조건 조회를 할 경우,
MongoDB는 $regex 오퍼레이터를 사용하여 정규식으로 해당 조건과 일치하는 도큐먼트를 조회합니다.
최적의 조회 성능을 위해 아래 사항을 숙지해야 합니다.
1. String 타입 필드에 인덱스가 생성되어 있지 않으면 대상 컬렉션에 풀스캔이 발생한다.
2. 인덱스가 생성되어 있을 경우, 일치 조건(eq = /keyword/)은 인덱스를 사용한다.
3. 인덱스가 생성되어 있을 경우, 접두어 조건(startsWith = /^keyword/) 또한 인덱스를 사용한다.
4. 인덱스가 생성되어 있더라도, 접미어 조건(startsWith = /keyword$/)은 인덱스를 사용하지 않는다.
5. 인덱스가 생성되어 있더라도, 포함 조건(contains = /.*keyword.*/)은 인덱스를 사용하지 않는다.
- 접미어 조건(endsWith = /keyword$/)은 위에 정리했듯이 인덱스를 사용하지 않아 컬렉션에 풀스캔이 발생합니다. 접미어에도 인덱스를 사용하고 싶다면, 해당 필드의 문자 순서를 거꾸로 뒤집은 필드를 생성하고 인덱스를 생성하면 됩니다.
- 풀텍스트 검색(FTS)을 원한다면 text 인덱스를 생성하면 됩니다.
유의할 점은 현재 공식적으로 영어권의 문자열만 FTS를 지원하기 때문에 CJK 계열의 한글 문자열의 경우 형태소 분석이 되지 않아 의도한대로 작동하지 않을 수 있습니다.
대안으로서의 방법은, 애플리케이션에서 자체적인 한글 형태소 분석기를 사용하여 해당 필드 값을 명사 단위로 쪼갠 후 중복을 제거한 배열 필드를 생성하고 인덱스를 생성하면 됩니다. (오픈 소스 한글 형태소 분석기인 KOMORAN을 사용. [관련 링크])
그외 인덱스 종류
- multikey index(배열일 경우 사용)
- geospatial index(지도)
- text index(text 검색)
- hash index(hash 인덱스 속도는 좋으나, 정렬이 안됨)
몽고디비 인덱스 문법
인덱스 생성
db.book.createIndex({name:1}) // name키에 인덱스 설정
db.book.createIndex({name:"text"}) // name키에 덱스트 인덱스 생성
인덱스 조회
인덱스는 처음 db를 만들 때 자동으로 생성되는 system.indexes 컬렉션에 저장됩니다.
db.book.getIndexes();
인덱스 제거
특정 인덱스를 제거하려면
// 특정 인덱스 제거
db.book.dropIndex(필드이름);
// 모두 제거
db.book.dropIndexes();
인덱스 조합
몽고DB는 똑똑하게 여러 인덱스를 조합합니다.
만약 name필드와 hp필드에 대한 인덱스가 따로 있으면,
db.monsters.find({ name: 'Slime', hp: { $gt: 10 } })
를 할 경우, 두 인덱스를 모두 사용하여 조회합니다.
인덱스 단점
인덱스의 단점은 인덱스 자체가 용량을 차지한다는 겁니다.
db.monsters.totalIndexSize();
위의 인덱스 하나를 설정했더니 16kb를 잡아먹게 됩니다.
너무 많은 인덱스를 사용해서 용량을 낭비하지 않도록 합시다.
이 글이 좋으셨다면 구독 & 좋아요
여러분의 구독과 좋아요는
저자에게 큰 힘이 됩니다.