MongoDB 최적화

devstone·2021년 11월 28일
9

MongoDB

목록 보기
1/1
post-thumbnail

🙈 Prologue

MongoDB 최적화에 대해 CTO님께서 해주신 강연(?)을 듣고 정리해보았습니다.

1. 잘못 설계된 사례

  • 온코파 2018 시즌2) lecture 콜렉션의 student필드에 배열 무한대로 늘리는 식으로 설계 → 10만명이 넘어가자 터짐

해결책

  • 배열의 크기가 제한된 범위가 아니라면 무조건 document에서 분리하는 식으로 해결
  • 새로운 콜렉션 user_lecture / user_lecture 이런 식으로 분리해서 user_id를 uniqueKey로 해서 lecture index를 저장

why?

  • 서비스에 맞지 않는 데이터 구조
  • 터질 것을 예상하지 못함 (어디까지 버틸지)

2. 몽고디비 최적화

2-1. 용량 최적화

  1. 필요한 데이터만 저장 : noSQL의 장점 ) field의 default 설정도 신중하게 → 도큐먼트에 들어가는 값 하나하나가 용량이다
  2. 사용하지 않는(않을) 데이터들은 제거
    1. TTL index : 특정 field값을 기준으로 일정 기간이 지나면 자동으로 삭제 ) 알림 기능에 적합
    2. Atlas Online Archive (몽고 디비 자체는 아니고 Atlas라는 플랫폼에서 제공해줌) : 자주 접근하지 않는 데이터를 Object Storage로 이전 (Data Lake) → 읽기 쿼리만 가능해서 로그 타입의 데이터에 적합
  3. compact command
    1. 일종의 디스크 조각 모음 : 데이터를 지우면 논리적 빈 공간이 생성되지만 즉시 물리 공간이 반환되지는 않음
    2. 몽고디비에서 db.runCommand({compact: "collection"})하면 빈 공간이 물리적 공간으로 반환됨. 그렇지만 너무 자주 남발하는 것은 좋지 않음.

2-2. Schema 최적화(=설계)

  • user 콜렉션에서 contact, access 정보를 따로 콜렉션으로 빼내어 같은 objectId 공유. → 최적화 가능, 그렇지만 쿼리 요청을 두 번 보내야 하므로 무조건 좋은 것은 아님 (→index를 고려해 결정해야 한다)
  • schema 최적화의 방점: document의 크기가 2mb를 넘지 않게. size limit 16mb, depth limit 100이지만 꽉 채우진 말자..
  • 어떤 필드를 index로 사용해 쿼리를 날릴지 고려 (굳이 인덱스가 아니더라도 이 데이터가 불리는 시나리오상 어떤 필드를 가지고 주로 데이터를 조회할 것인지)

2-3.Query 최적화

  1. select : 꼭 필요한 필드만 필터링 해서 들고 오기(트래픽, 메모리 → 디비가 메모리를 올려서 얘를 서빙하므로 내 쿼리가 메모리를 적게 쓰면 그만큼 다른 쿼리를 처리할 수 있는 능력이 늘어난다)
  2. limit : 데이터를 가져오는 개수를 제한 - 한번에 다 필요하지도 않은데 막 만개씩 데이터를 들고온다든지. 사용자가 보통 만개의 데이터를 한 번에 보는 경우는 없으므로. 데이터가 많은 경우 limit을 걸어서 잘라서 가져오는 것이 좋다
  3. index를 활용: index를 활용해 콜렉션 내의 모든 도큐먼트들을 검토하지 않고 데이터를 디비가 찾을 수 있게 도와줘야 함.

3. index

3-1. index란?

  • 콜렉션 데이터의 일부를 저장해 탐색을 쉽게 해주는 특별한 자료구조 (-공식문서)
  • 인덱스가 아닌 다른 것을 기준으로 정렬하거나 하려고 하면 전체를 탐색해야해서 인덱스를 최대한 활용하는 것이 좋다 !
  • B-Tree : 데이터를 항상 정렬된 상태로 유지
  • 우리 서비스에서 주로 사용하는 index
    1. single index : 하나의 인덱스를 기준으로 데이터를 정렬
    2. compound index : 필드 두 개를 기준으로 데이터를 정렬 . 필드 순서와 정렬 순서가 매우 중요
      {userid : 1 , score: -1} → userid는 오름차순, score은 내림차순 / userid 가 먼저 정렬, score은 후순위로. 그래서 순서가 중요함
      - userid로는 찾거나 정렬 할 수 있지만 score로는 힘듦
      - prefix : 다른 필드를 주지 않더라도 그 자체로 찾거나 정렬 가능한 필드

우리의 목표: 최대한 적은 수의 인덱스로 최대한 많은 종류의 query를 커버하는 것

3-2. 인덱스 설계 전략

1. Query의 selectivity를 높인다

  1. 값이 최대한 유니크한 필드를 index로 선정
  2. index 기준으로 정렬했을 때 값이 골고루 분포되어야 있어야 함.
  3. 데이터가 뭉쳐있는 부분이 적어야 좋다.
    Ex. user.id, user.signup_date - 거의 겹치지 않는 값들, index로 삼기에 좋다.
    1. 사용자 시나리오에서 어떤 필드를 중심으로 데이터가 자라날 지에 대한 것 고려하기

2. 인덱스가 만능은 아니다

  1. index의 단점은 쓰기 성능 저하, 저장공간 차지
  2. index가 많다고 무조건 좋은 것은 아니다
  3. 쓰기가 많이 일어나면 복잡한 index는 만들지 않는다.
  4. 나의 query가 전혀 의도하지 않은 index를 탈 수도 있다.
    • 몽고 디비가 index를 선택하는 방식 때문: 모든 index에 query를 날려 100개(정확 x)의 document를 가장 빨리 가져오는 index를 선택한다고 한다
    • 찝찝하면 테스트 필수

3. 지속적으로 관리해야 한다

  1. 기능이 추가, 변경되면 데이터 모델과 쿼리도 추가, 변경
  2. 변경된 상황에 맞게 Index를 추가하거나, 사용하지 않게된 index는 제거한다.
.explain('exexuteTime어쩌구').. 수행시간 측정 가능
profile
개발하는 돌멩이

1개의 댓글

comment-user-thumbnail
2021년 12월 5일

아악 뭔소리야 한글번역이 제대로 안됬는데요?

답글 달기