[database-design] MongoDB 스키마 설계-작은 문서가 많거나 큰 문서가 적습니까?

배경
RDBMS 데이터베이스에서 MongoDB 로의 변환을 프로토 타이핑하고 있습니다. 비정규 화하는 동안 두 가지 선택이있는 것 같습니다. 하나는 많은 (수백만) 개의 작은 문서로 이어지고 다른 하나는 더 적은 (수만 개의) 큰 문서로 이어집니다.

간단한 아날로그로 정리할 수 있다면 다음과 같은 고객 문서가 적은 컬렉션 (Java) 간의 차이 일 것입니다.

class Customer {
    개인 문자열 이름;
    개인 주소 주소;
    // 각 신용 카드에는 수백 개의 결제 인스턴스가 있습니다.
    개인 Set <CreditCard> creditCards;
}

또는 다음과 같은 많은 결제 문서가 포함 된 컬렉션 :

class Payment {
    개인 고객 고객;
    개인 신용 카드 신용 카드;
    개인 날짜 payDate;
    private float payAmount;
}

질문
MongoDB는 많은 작은 문서를 선호하거나 적은 수의 큰 문서를 선호하도록 설계 되었습니까? 대답은 주로 내가 실행할 쿼리에 따라 달라 집니까? (즉, 고객 X는 몇 개의 신용 카드를 가지고 있습니까? vs 모든 고객이 지난달에 지불 한 평균 금액은 얼마입니까?)

나는 많이 둘러 보았지만 내 질문에 대답하는 데 도움이 될 MongoDB 스키마 모범 사례를 발견하지 못했습니다.



답변

수행중인 쿼리에 맞게 최적화해야합니다.

귀하의 설명을 기반으로 한 내 최선의 추측입니다.

각 고객에 대한 모든 신용 카드를 알고 싶을 것이므로 고객 개체 내에 신용 카드 배열을 유지하십시오. 또한 각 결제에 대한 고객 참조를 원할 수도 있습니다. 이렇게하면 지불 문서가 비교적 작게 유지됩니다.

결제 개체는 자동으로 자체 ID와 색인을 갖습니다. 고객 참조에도 색인을 추가하고 싶을 것입니다.

이렇게하면 매번 전체 고객 개체를 저장하지 않고도 고객 별 결제를 빠르게 검색 할 수 있습니다.

“모든 고객이 지난달에 지불 한 평균 금액은 얼마입니까?” 와 같은 질문에 답하려는 경우 하려면 대신지도를 원하거나 크기가 큰 데이터 세트에 대한 축소를 원할 것입니다. 이 응답은 “실시간”이 아닙니다. 고객에 대한 “참조”를 저장하면 이러한 맵 축소에 충분할 것입니다.

따라서 귀하의 질문에 직접 답하려면 MongoDB가 많은 작은 문서를 선호하도록 설계 되었습니까?

MongoDB는 인덱싱 된 항목을 매우 빠르게 찾을 수 있도록 설계되었습니다. MongoDB는 큰 건초 더미에서 몇 개의 바늘 을 찾는 데 매우 능숙 합니다. MongoDB는 건초 더미에서 대부분 의 바늘 을 찾는 데 그다지 좋지 않습니다 . 따라서 가장 일반적인 사용 사례를 중심으로 데이터를 구축하고 드문 사용 사례에 대한 매핑 / 감소 작업을 작성하십시오.


답변

MongoDB의 자체 문서에 따르면 많은 작은 문서를 위해 설계된 것처럼 들립니다.

에서 MongoDB를위한 성능 모범 사례 :

MongoDB에서 문서의 최대 크기는 16MB입니다. 실제로 대부분의 문서는 몇 킬로바이트 이하입니다. 테이블 자체보다 테이블의 행과 더 유사한 문서를 고려하십시오. 단일 문서에서 레코드 목록을 유지하는 대신 각 레코드를 문서로 만듭니다.

에서 제 1 부 : MongoDB의 스키마 설계를위한 엄지 손가락의 6 명 규칙 :

일대일 모델링

“일대일”의 예로는 사람의 주소가 있습니다. 이것은 임베딩에 대한 좋은 사용 사례입니다. 주소를 Person 객체 내부의 배열에 넣습니다.

일대 다

“일대 다”의 예로는 교체 부품 주문 시스템의 제품 부품이 있습니다. 각 제품에는 최대 수백 개의 교체 부품이있을 수 있지만 몇 천 개를 넘지 않아야합니다. 이것은 참조를위한 좋은 사용 사례입니다. 제품 문서의 배열에 부품의 ObjectID를 넣습니다.

일 대규모

“일대 스퀼 리온”의 예로는 다른 시스템에 대한 로그 메시지를 수집하는 이벤트 로깅 시스템이 있습니다. 배열에 저장된 모든 것이 ObjectID 인 경우에도 주어진 호스트는 16MB 문서 크기를 오버플로 할 수있는 충분한 메시지를 생성 할 수 있습니다. 이것은 “상위 참조”의 전형적인 사용 사례입니다. 호스트에 대한 문서가 있고 로그 메시지 용 문서에 호스트의 ObjectID를 저장합니다.


답변

시간이 지남에 따라 크게 증가하는 문서는 시한 폭탄이 될 수 있습니다. 네트워크 대역폭과 RAM 사용량은 측정 가능한 병목 현상이되어 처음부터 다시 시작해야합니다.

먼저 고객과 결제라는 두 가지 컬렉션을 고려해 보겠습니다. 따라서 곡물은 상당히 작습니다. 지불 당 하나의 문서입니다.

다음으로 신용 카드와 같은 계정 정보를 모델링하는 방법을 결정해야합니다. 고객 문서에 계정 정보 배열이 포함되어 있는지 또는 새 계정 컬렉션이 필요한지 고려해 보겠습니다.

계정 문서가 고객 문서와 별 개인 경우 한 고객의 모든 계정을 메모리에로드하려면 여러 문서를 가져와야합니다. 이는 추가 메모리, I / O, 대역폭 및 CPU 사용량으로 변환 될 수 있습니다. 그것은 즉시 계정 컬렉션이 나쁜 생각이라는 것을 의미합니까?

귀하의 결정은 지불 문서에 영향을 미칩니다. 고객 문서에 계정 정보가 포함되어있는 경우 어떻게 참조 하시겠습니까? 별도의 계정 문서에는 자체 _id 속성이 있습니다. 포함 된 계정 정보를 사용하면 애플리케이션이 계정에 대한 새 ID를 생성하거나 키에 계정의 속성 (예 : 계정 번호)을 사용합니다.

지불 문서에 실제로 고정 된 기간 (예 : 요일)에 이루어진 모든 지불이 포함될 수 있습니다. 이러한 복잡성은 지불 문서를 읽고 쓰는 모든 코드에 영향을 미칩니다. 조기 최적화는 프로젝트에 치명적일 수 있습니다.

계정 문서와 마찬가지로 지불 문서에 지불이 하나만 포함되어 있으면 지불을 쉽게 참조 할 수 있습니다. 예를 들어 신용과 같은 새로운 유형의 문서는 지불을 참조 할 수 있습니다. 하지만 크레딧 컬렉션을 생성 하시겠습니까, 아니면 결제 정보에 크레딧 정보를 포함 하시겠습니까? 나중에 크레딧을 참조해야한다면 어떻게됩니까?

요약하면, 저는 많은 작은 문서와 많은 컬렉션으로 성공했습니다. _id와 _id로만 참조를 구현합니다. 따라서 계속 늘어나는 문서가 내 애플리케이션을 파괴하는 것에 대해 걱정하지 않습니다. 스키마는 각 항목에 자체 컬렉션이 있으므로 이해하고 색인하기 쉽습니다. 중요한 엔터티는 다른 문서 안에 숨어 있지 않습니다.

나는 당신의 발견에 대해 듣고 싶습니다. 행운을 빕니다!


답변