스키마 설계 고려 사항
- 데이터 표현의 핵심 요소는 데이터가 도큐먼트에서 표현되는 방식인 스키마 설계다.
- 가장 좋은 설계 접근 방식은 애플리케이션에서 원하는 방식으로 데이터를 표현하는 방법이다.
- 따라서 관계형 DB와 달리, 스키마를 모델링하기 전에 먼저 쿼리 및 데이터 접근 패턴(data access pattern)을 이해해야 한다.
적용할 수 있는 스키마 설계 패턴
다형성 패턴(polymorphic pattern)
- 컬랙션 내 모든 도큐먼트가 유사하지만 동일하지 않은 구조를 가질 때 적합하다.
- 여기에는 (애플리케이션에서 실행할) 공통 쿼리를 지원하는 도큐먼트에서 공통 필드를 식별하는 것이 포함됨.
- 도큐먼트나 서브도큐먼트의 특정 필드를 추척하면, 이러한 차이점을 관리하기 위해 애플리케이션에서 코딩할 수 있는 데이터와 다른 코드 경로 또는 클래스 / 서브클래스 간의 차이점을 식별하는데 도움이 된다.
- 이를 통해 동일하지 않은 도큐먼트로 구성된 단일 컬렉션에서 간단한 쿼리를 사용해 쿼리 성능을 향상시킬 수 있다.
속성 패턴(attribute pattern)
- 정렬하거나 쿼리하려는(공통 특성을 갖는) 도큐먼트에 필드의 서브셋이 있는 경우
- 정렬하려는 필드가 도큐먼트의 서브셋에만 존재하는 경우
- 또는 두 조건이 모두 해당되는 경우에 적합하다.
- 이 패턴은 도큐먼트당 많은 유사한 필드를 대상으로 지정하기 때문에 필요한 인덱스가 적어지고 쿼리 작성이 더 간단해진다.
버킷 패턴(bucket pattern)
- 데이터가 일정 기간 동안 스트림으로 유입되는 시계열 데이터에 적합하다.
- 몽고DB에서 이 데이터를 특정 시간 범위의 데이터를 각각 보유하는 도큐먼트 셋으로 '버킷화'하면 시간/데이터 포인트의 포인트당 도큐먼트를 만들 때보다 훨씬 효율적이다.
- 도큐먼트 자체에는 이 '버킷'이 다루는 기간을 나타내는 시작 및 종료시간이 있다.
이상치 패턴(outlier pattern)
- 이상치 패턴은 드물게 도큐먼트의 쿼리가 애플리케이션의 정상적인 패턴을 벗어날 때 사용한다.
- 인기도(popularity)가 중요한 상황을 위해 설계된 고급 스키마 패턴으로, 주요 영향 요인, 도서 판매, 영화 리뷰 등이 있는 소셜 네트워크에서 볼 수 있다.
계산된 패턴(computed pattern)
- 데이터를 자주 계산해야 할 때나 데이터 접근 패턴이 읽기 집약(read-intensive)일 때 사용한다.
- 이 패턴은 도큐먼트가 주기적으로 갱신되는 백그라운드에서 계산을 수행하도록 권장한다.
- 이는 개별 쿼리에 대해 필드나 도큐먼트를 지속적으로 생성하지 않고도 계산된 필드 및 도큐먼트의 유효한 근사치를 제공한다.
- 읽기가 계산을 트리거(trigger)하고 읽기-쓰기 비율이 높은 경우에 특히 동일한 계산의 반복을 방지함으로써 CPU에 가해지는 부담을 크게 줄일 수 있다.
서브셋 패턴(subset pattern)
- 장비의 램 용량을 초과하는 작업 셋이 있을 때 사용한다.
- 이는 애플리케이션에서 사용하지 않는 정보를 많이 포함하는 대용량 도큐먼트 때문에 발생할 수 있다.
- 서브셋 패턴은 자주 사용하는 데이터와 자주 사용하지 않는 데이터를 두개의 개별 컬렉션으로 분할하도록 한다.
확장된 참조 패턴(extended reference pattern)
- 각각 고유한 컬렉션이 있는 여러 논리 엔티티 또는 '사물'이 있고, 특정 기능을 위해 엔티티들을 모을 때 사용한다.
- 확장된 참조 패턴은 데이터를 중복시키는 대신 정보를 조합하는데 필요한 쿼리 수를 줄인다.
근사 패턴(approximation pattern)
- 리소스가 많이 드는(시간, 메모리, CPU 사이클) 계산이 필요하지만 높은 정확도가 반드시 필요하지 않은 상황에 유용하다.
- 이미지나 게시글의 추천 수 카운터 또는 페이지 조회 수 카운터를 예로 들 수 있다.
- 근사 패턴을 적용해 추천이나 조회수가 1회가 아니라 100회가 될 때마다 카운터를 갱신하면 쓰기 횟수를 크게 줄일 수 있다.
트리 패턴(tree pattern)
- 쿼리가 많고 구조적으로 주로 계층적인 데이터가 있을 때 적용한다.
- 일반적으로 함께 쿼리되는 데이터를 한데 저장하는 방식을 따른다.
- 몽고DB에서는 동일한 도큐먼트 내 배열에 계층구조를 쉽게 저장할 수 있다.
사전 할당 패턴(preallocation pattern)
- 주로 MMAP 스토리지 엔진과 함께 사용됐지만 여전히 사용된다.
- 이 패턴은 빈 구조(나중에 채워진다)를 사전 할당한다.
- 예를 들어 예약 정보를 매일 관리하는 시스템에서, 예약 가능 여부와 현재 예약 상태를 추적하는데 적용된다.
- 리소스(x)와 날짜(y)의 2차원 구조를 사용해 쉽게 가용성을 확인하고 계산할 수 있다.
도큐먼트 버전 관리 패턴(document versioning pattern)
- 도큐먼트의 이전 버전을 유지하는 매커니즘을 제공한다.
- '메인' 컬렉션의 도큐먼트 버전을 추적하려면 각 도큐먼트에 부가 필드를 추가해야 하며 도큐먼트의 모든 수정 사항을 포함하는 추가 컬렉션이 필요하다.
- 패턴에는 몇가지 가정이 있다.
- 각 도큐먼트의 개정은 횟수가 제한되고,
- 버전 관리가 필요한 도큐먼트가 많지 않으며,
- 쿼리는 각 도큐먼트의 현재 버전에서 먼저 수행된다.
- 이러한 가정이 유효하지 않을 때는 패턴을 수정하거나 다른 스키마 설계 패턴을 고려해야 할 수 있다.
내장 방식과 참조 방식 비교
내장 방식이 좋은 경우
- 작은 서브도큐먼트
- 주기적으로 변하지 않는 데이터
- 결과적인 일관성이 허용될 때
- 증가량이 적은 도큐먼트
- 두 번째 쿼리를 수행하는데 자주 필요한 데이터
- 빠른 읽기
참조 방식이 좋은 경우
- 큰 서브도큐먼트
- 자주 변하는 데이터
- 즉각적인 일관성이 필요할 때
- 증가량이 많은 도큐먼트
- 결과에서 자주 제외되는 데이터
- 빠른 쓰기
데이터 조작을 위한 최적화
애플리케이션을 최적화하려면 읽기와 스기 성능을 분석해 어느 것이 병목 현상을 일으키는지 우선적으로 알야한다.
읽기 최적화는 일반적으로 올바른 인덱스를 사용해 하나의 도큐먼트에서 가능한 한 많은 정보를 반환하는 것과 관련 있다.
쓰기 최적화는 보통 갖고 있는 인덱스 개수를 최소화하고 갱신을 가능한 한 효율적으로 수행하는 것과 관련 있다.
빠른 쓰기에 최적화된 스키마와 빠른 읽기에 최적화된 스키마 사이에는 종종 트레이드 오프가 존재하므로, 어느 것이 애플리케이션에 더 중요한지 결정해야 한다.
쓰기와 읽기의 중요도뿐 아니라 이들의 비율 또한 최적화 요소이다.
애플리케이션에서는 쓰기가 더 중요하지만 각 쓰기에 대해 읽기를 수천 번 수행한다면 읽기를 먼저 최적화하면 좋다.