SMAIVNN
article thumbnail
Published 2023. 3. 24. 22:14
[mongoDB] 인덱스 Database

인덱스란?

인덱싱은 책의 목차와 같다. 원하는 데이터를 찾고자 처음부터 끝까지 찾는게 아닌, 목차를 보고 원하는 부분으로 바로 가서 찾는 것으로 이해하면 좋다. 이처럼 자주 조회되는 필드(데이터)에 대해 따로 저장을 진행하여 탐색 속도를 빠르게 한다.

따로 저장을 진행하므로 일정 용량을 차지한다.

언제 사용하는가?

정의만 보면 좋아보이지만, 단점이 명확히 있다. 인덱싱 된 필드에 쓰기(삽입, 갱신, 삭제)작업은 오래 걸린다는 것이다.

쓰기 작업 이후 데이터가 변경될 때 마다 도큐먼트만이 아닌 모든 인덱스를 갱신한다.

 

적합한 쿼리 구성

인덱스를 진행할 필드의 선정은 자주쓰는 쿼리, 빨리 수행해야 하는 쿼리를 조사해 공통적인 키 셋을 찾아 진행하도록 한다. 독특한 쿼리, 관리자에 의해 실행되는 쿼리 등 소요 시간에 구애받지 않는 필드는 적합하지 않다.(소요 시간을 빠르게 하고자 사용하기 때문)

 

인덱스는 모든 값을 정렬된 순서로 보관하기에 인덱스 키(필드)로 도큐먼트 정렬하는 작업이 훨씬 빨라진다. 하지만 이는 인덱스가 앞쪽에 놓일 때만 도움이 된다.

예를들어 인덱스는 현재 username에 걸려있다.

model.find().sort({"age" : 1, "username" : 1})

위 코드는 age필드가 우선순위로 되어있기에 도움이 되지 않는다. 이 쿼리에서 정렬을 최적화 하기 위해서는 age와 username 모두에 인덱스를 만들어야 한다.

 

복합 인덱스

우리가 사용하는 상당수의 쿼리 패턴은 두 개 이상의 키(필드)를 기반으로 인덱스를 작성한다. 따라서 두 개 이상의 필드에 인덱스 정렬을 최적화 하려면 앞서 말했듯 두 개의 필드에 모두 인덱스를 만든다. 

model.createIndex({"age" : 1, "username" : 1});

이를 복합 인덱스라고 한다.

 

복합 인덱스의 키를 구성할 때, 구성 순서에서도 고려할 것이 있다. 가령 다음과 같은 코드가 쿼리를 한다고 가정하자.

model.find({student_id:{$gt:5000}, class_id:54})
	.sort({final_grade:1})
	.explain("executionStats") // 인덱스 관련 정보를 보는 코드이다, 지금은 무시하자.

이 쿼리는 student_id가 5000보다 높은, class_id가 54번인 데이터를 찾아 final_grade를 기준으로 정렬하는 쿼리이다. 각각 다중값(범위) 필터, 동등 필터, 정렬 구성 요소라고 부를수 있다.

 

student_id가 5000보다 높은 것을 모두 탐색한 후, 그 중 class_id가 54번인 데이터를 찾은 후 정렬하는 것보다. 바로 class_id가 54인 데이터를 찾은 후 그 중에서 student_id가 5000이상인 것을 찾는것이 더 빠를 것이다.

 

이처럼 일반적으로 복한 인덱스를 동등 필터 필드를 다중값 필터 필드보다 앞에 오도록 설계한다. 

- 동등 필터 키는 맨 앞에 표시한다.

- 정렬에 사용되는 키는 다중 값 필드 앞에 표시한다.

- 다중값 필터 필드에 대한 키는 마지막에 표시한다.

 

그렇게 구현된 인덱스 키는 [class_id, ginal_grade, student_id] 순서로 설계된다.

 

암시적 인덱스

{ "a" : 1 ,"b" : 1 ,"c" : 1 ,"d" : 1 ,"e" : 1 .... "z" : 1 } 인덱스가 있다면 이 앞쪽 묶음은 모두 공짜 인덱스가 된다.

{ "a" : 1 }, { "a" : 1, "b" : 1 } { "a" : 1, "b" : 1, "c" : 1 }는 모두 인덱스를 갖는다 하지만 {"b": 1 }나 {"a" : 1, "c" : 1 }는 최적화 되지 않는다.

 

커버드 쿼리

작성한 쿼리가 인덱스에 포함된 필드를 바로 찾는다면 도큐먼드를 직접 가져올 필요가 없다. 인덱스가 쿼리가 요구하는 값(필드)을 모두 포함한다면 쿼리가 커버드(covered)되었다고 한다. 이를 커버드 쿼리라고 한다.

 

인덱스 카디널리티

카디널리티는 컬렉션의 한 필드 내에 고유한 값이 얼마나 많은지 나타낸다. 예를들어 gender는 가질 수 있는 값이 2개 뿐이며 낮은 카디널리티를 갖는다. username, email등은 고유한 값을 갖으며 높은 카디널리티이다. age나 zipCode 등은 중간쯤 해당한다. 

 

일반적으로 카디널리티가 높을수록 인덱싱에 도움이 된다. 따라서 높은 카디널리티를 갖는 키를 생성하면 좋다. 그러니 복합 인덱스를 구성할 때 높은 카디널리티 키를 낮은 카디널리티 키보다 앞에 놓자.

 

인덱스를 생성하지 않는 경우

인덱스가 적합한 경우는 다음과 같다.

- 큰 컬렉션

- 큰 도큐먼트

- 선택적 쿼리

 

컬렉션 스캔이 더욱 적합한 경우는 다음과 같다.

- 작은 컬렉션

- 작은 도큐먼트

- 비 선택적 쿼리

 

제한 컬렉션

일반적인 컬렉션은 동적으로 생성되며 데이터가 추가됨에 따라 크기가 자동으로 커진다. 하지만 제한 컬렉션이라는 크기가 고정된 다른 형태의 컬렉션을 만들 수 있다. 이 컬렉션은 크기가 제한되어 있다. 만약 이 제한된 크기가 가득 찬 상태에서 추가로 데이터를 쓴다면 오래된 데이터는 지워지고 새로운 데이터가 추가된다. 즉, 환형 큐처럼 사용할 수 있는 것이다.

 

이는 디스크가 고정된 영역에 데이터가 순서대로 저장되므로 쓰기를 다소 빠르게 수행할 수 있으며 주로 로깅 작업 등에 사용된다. 하지만 다음과 같은 특징을 갖는다.

- 제한 컬렉션은 샤딩될 수 없다.

- 오래된 순으로 지워질 때 제어할 수 없다.

- 자동 삭제 외에 임의로 데이터를 삭제할 수 없다.

 

추후 TTL(time to live)관련 정리.

본 게시물은 한빛미디어의 <MongoDB The Definitive Guide 몽고DB 완벽 가이드 3>을 요약 정리했습니다.

'Database' 카테고리의 다른 글

[mongoDB] 집계 프레임워크  (0) 2023.03.25
[mongoDB] 쿼리  (0) 2023.03.17
[mongoDB] 갱신 연산자  (0) 2023.03.15
profile

SMAIVNN

@SMAIVNN

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!