본문으로 바로가기

https://velopert.com/560

https://blog.ull.im/engineering/2019/04/05/mongodb-indexing-strategy.html 키를 이용한 검색 최적화

https://www.zerocho.com/category/MongoDB/post/57a6faddc90c5815005babc3

 

 

내용 이해를 위해 위 게시물을 확인해 봅시다.

 

인덱스?

 

자주 조회되는 필드를 따로 저장해서 조회 및 정렬 시의 속도를 빠르게 하는 기법입니다.

 

검색을 더 빠르게 수행하고자 데이터를 추가하기 때문에 용량을 희생하고(그래봐야 속성 하나일 뿐이긴 합니다), 속도를 올리는 결과를 가져오게 됩니다. DB 사용에 있어 인덱스 사용은 필수입니다.

 

index가 없으면 컬렉션에 있는 도큐먼트를 컴퓨터가 한땀한땀 조회한다. 물론 수백개의 도큐먼트 따위는 금방 조회하기 때문에 차이가 느껴지지 않지만, 도큐먼트가 수백만개가 되면 이야기가 달라집니다. 인덱스를 활용하면 더 적은 횟수의 조회로 원하는 결과물을 얻을 수 있게 됩니다.

 

 

 

- 기본 인덱스 _id

 

모든 mongoDB 도큐먼트는 기본적으로 _id를 가지고 있습니다.

이 _id에는 자동으로 인덱스 설정이 되어 있습니다. 

따라서 무언가를 찾을 때, _id를 기반으로 찾으면 빠르게 찾을 수 있습니다.

 

 

- single(단일) 필드 인덱스

 

# create_index 로 인덱스 생성. 검색을 자주할 것 같은 속성으로 지정하면 됨
actor_collection.create_index('배우이름')

# 특정 direction을 주고 싶다면 다음과 같이 지정한다.
actor_collection.create_index([('흥행지수', -1)])
actor_collection.create_index([('출연영화', 'text')])

# 인덱스 정보 출력
actor_collectio.index_information()

# 인덱스 전부 삭제(_id는 유지됨)
actor_collection.drop_indexes()

# 특정 인덱스만 삭제. key 값만 넣어주면 된다.
actor_collection.drop_indexes([('배우이름', 1)])

 

인덱스 정보를 출력한 결과 다음과 같이 인덱스가 조회되었다.

 

{'_id_': {'v': 2, 'key': [('_id', 1)], 'ns': 'cine21.actor_collection'}, //_id는 기본적으로 가지고 있음

 

'배우이름_1': {'v': 2, 'key': [('배우이름', 1)], 'ns': 'cine21.actor_collection'},

 

'흥행지수_-1': {'v': 2, 'key': [('흥행지수', -1)], 'ns': 'cine21.actor_collection'},

 

'출연영화_text': {'v': 2, 'key': [('_fts', 'text'), ('_ftsx', 1)], 'ns': 'cine21.actor_collection', 'weights': SON([('출연영화', 1)]), 'default_language': 'english', 'language_override': 'language', 'textIndexVersion': 3}}

 

_id 라는 인덱스와 배우이름_1, 흥행지수_-1, 출연영화_text이라는 인덱스가 조회되었다. 

여기서 배우이름_1은 key 값이 [('배우이름', 1)] 라는 것이다.

 

여기서 key에 주어진 값을 조금 더 살펴보자면,

 

key : ('필드명', direction)

  • direction
    • pymongo.ASCENDING = 1
    • pymongo.DESCENDING = -1
    • pymongo.TEXT = 'text'

 

 

그렇다면 해당 인덱스를 어떻게 활용할 수 있는가?

 

다음과 같이 인덱스를 만들어 줬다 가정하면,

actor_collection.create_index('배우이름')
actor_collection.create_index([('흥행지수', -1)])
actor_collection.create_index([('출연영화', 'text')])

 

text 형식인 인덱스는 다음과 같이 활용한다. '신과'가 포함된 출연영화를 검색한다.

for i in actor_collection.find({'$text': {"$search": '신과'}}):
    print(i)

 

 

- compound(복합) 필드 인덱스

 

 

최대 31개의 필드로 만들 수 있다.

여기서는 2개의 필드를 가진 복합 인덱스를 만들 수 있다.

 

db.students.createIndex({ userid: 1, score: -1 })

 

컴파운드 인덱스에서의 주의할 점은, 위 예시의 경우, userid에 대한 인덱스와 score에 대한 인덱스가 각각 생기는 것이 아니라, userid에 대한 오름차순 정렬을 먼저 한 뒤, 점수를 내림차순 정렬을 한다는 것입니다.

 

이를 시각화해보면 다음과 같습니다.

 

먼저 유저로 정렬되어 있고, 그 이후 점수로 정렬되어 있다면, 점수만 검색할 때 점수에 index를 줬다고 검색 기능에 향상이 있을까요? 아닙니다. 그러나 유저와 함께 점수를 조회한다면 검색 결과가 향상될 것입니다.

 

이 말인 즉슨, find를 하는 순서도 중요하다는 겁니다.

db.collection.createIndex({ a: 1, b: 1 })

// 성능이 좋습니다
db.collection.find().sort({ a: 1, b: 1 })
// 성능이 좋지 않습니다
db.collection.find().sort({ b: 1, a: 1 })

 

또한, 오름/내림차순의 정렬 순서도 중요합니다.

상상해봅시다. a를 오름차순 b를 내림차순으로 정리했습니다.

이를 뒤집으면 a는 내림차순, b를 오름차순으로 정렬한 것입니다. (연산이 따로 필요하지 않습니다.)

따라서 아래와 같은 성능이 나올 것으로 추측할 수 있습니다.

 

db.collection.createIndex({ a: 1, b: -1 })

// 성능이 좋습니다
db.collection.find().sort({ a: 1, b: -1 })
db.collection.find().sort({ a: -1, b: 1 })
// 성능이 좋지 않습니다
db.collection.find().sort({ a: 1, b: 1 })
db.collection.find().sort({ a: -1, b: -1 })

 


darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체