본문 바로가기
Infra/MongoDB

MongoDB - (10) - 애플리케이션 설계(3)

by Inventer 2023. 4. 24.

연결된 포스팅이다 이전 글을 참고하라.

 

  1. 스키마 설계 고려 사항
  2. 데이터 embed 방식과 참조 방식 중 결정하기 - (현재지점)
  3. 최적화를 위한 팁
  4. 일관성 고려 사항
  5. 스키마 마이그레이션 방법
  6. 스키마 관리 방법
  7. 몽고 DB가 데이터 스토리지로 적합하지 않은경우

 

정규화 및 비정규화

정규화 : 각 컬렉션 간의 참조를 이용해 여러 컬렉션으로 나누는 작업

비정규화 : 모든 데이터를 하나의 도큐먼트에 내장

 

비 정규화는 정보가 갱신되면 여러 도큐먼트가 갱신되야하지만, 하나의 쿼리로 모든 데이터를 가져올 수 있음을 뜻한다.

 

따라서 정규화는 RDBMS를 설계하는 방법과 매우 유사하며,

비정규화는 MongoDB의 특색을 잘 표현한다.

 

아래는 정규화스러운 데이터 표현 예제이다.

db.studentClasses.findOne({"studentId" : id})
{
    "_id" : ObjectId("512512c1d86041c7dca81915),
    "studentId" : ObjectId("512512c1d86041c7dca81105),
    "classes : [
    	ObjectId("512512c1d86041c7dca81916),
        ObjectId("512512c1d86041c7dca81917),
        ObjectId("512512c1d86041c7dca81918),
        ObjectId("512512c1d86041c7dca81919)
    ]
}

Classes에서 각 데이터를 가지고 있는것이 아닌, 다른 class라는 도큐먼트를 참고하고 있는 형태이다.

하지만 이는 한번의 데이터를 얻을 때 여러번 쿼리해야하기 때문에

일반적으로는 위와 같이 저장하지 않는다.

 

해당 정보를 아예 classes 내에서 보관한다.

 

아래는 보다 MongoDB 스러운 비정규화한 도큐먼트 구조이다.

db.studentClasses.findOne({"studentId" : id})
{
    "_id" : ObjectId("512512c1d86041c7dca81915),
    "name" : "John Doe",
    "classes : [
    	{
       	    "class" : "Math",
            "credits" : 3,
            "room" : "204"
        },
        {
            "class" : "History",
            "credits" : 3,
            "room" : "159"
        },
        {
            "class" : "English",
            "credits" : 3,
            "room" : "14b"
        },
        {
            "class" : "Physics",
            "credits" : 3,
            "room" : "321"
        }
    ]
}

 

위 처럼 저장하면 쿼리를 하나만 사용하여 모든 정보를 얻을 수 있지만,

더 많은 공간을 차지하고 동기화가 어렵다는 단점이 있다.

물리학이 3학점이 아닌 4학점이라면 위 예시의 도큐먼트를 수정하는 것이 아닌,

모든 학생의 도큐먼트를 수정해야할 일이 발생하는 것이다.

 

여기서 확장 참조 패턴을 사용하면 아래와 같이 바꿀 수 있다.

db.studentClasses.findOne({"studentId" : id})
{
    "_id" : ObjectId("512512c1d86041c7dca81915),
    "name" : "John Doe",
    "classes : [
    	{
            "_id" : ObjectId("512512c1d86041c7dca81916),
       	    "class" : "Math"
        },
        {
            "_id" : ObjectId("512512c1d86041c7dca81917),
            "class" : "History"
        },
        {
            "_id" : ObjectId("512512c1d86041c7dca81918),
            "class" : "English"
        },
        {
            "_id" : ObjectId("512512c1d86041c7dca81920),
            "class" : "Physics"
        }
    ]
}

장점이 보이는가?

 

이를 정리하고, 몇가지 예시를 들어본다.

내장 방식이 좋은 경우 참조 방식이 좋은 경우
작은 서브도큐먼트 큰 서브도큐먼트
주기적으로 변하지 않는 데이터 자주 변하는 데이터
결과적인 일관성이 허용될 때 즉각적인 일관성이 필요할 때
증가량이 적은 도큐먼트 증가량이 많은 도큐먼트
두 번째 쿼리를 수행하는데 자주 필요한 데이터 결과에서 자주 제외되는 데이터
빠른 읽기 빠른 쓰기

 

users 컬렉션이 존재할 때 아래와 같을 것이다.

계정 설정 - 내장

최근 활동 - 크기가 최근 10개 활동 처럼 고정된 경우 내장이 좋을 것 임

친구 - 내장하지 않는다.

사용자가 생성한 모든 내용 - 내장하지 않는다.

 

 

 

다음장 바로가기

https://inventer.tistory.com/31

 

댓글