비정규화

Sidebar 10.5

번역 완료율

이 장에서는:

  • 비정규화란 무엇인지를 이해한다.
  • Mongo를 전통적인 관계형 DB와 비교한다.
  • 언제 데이터를 비정규화하면 *안되는* 지를 배운다
  • 데이터를 비정규화한다는 것은 데이터를 “정규화"한 형태로 저장하지 않는다는 것을 의미한다 - 다른 말로 표현하면, 비정규화란 데이터의 같은 조각에 대한 여러 복사본을 가진다는 것을 의미한다.

    이전 장에서, 우리는 매 시점마다 댓글 전체를 로드하는 것을 피하기 위해서 post 객체에 연결된 comment의 숫자를 비정규화했다. 데이터 모델링의 관점에서는 불필요한 작업이다. 댓글의 숫자를 (성능 문제를 제외한다면) 어느 때나 계산할 수 있기 때문이다.

    비정규화는 개발자에게는 종종 추가작업을 의미한다. 위의 예제에서 댓글을 추가하거나 삭제하는 매 순간, post 정보를 갱신하여 항상 commentsCount 속성의 값을 정확하게 유지하여야 한다. 이런 이유로 MySQL과 같은 관계형 데이터베이스는 이런 방식을 못마땅해한다.

    그런데, 정규화 방식도 단점이 있다: commentsCount 속성이 없다면, 우리는 모든 댓글들을 내려보내어 그 갯수를 셀 수 있도록 해야 한다. 초기에는 우리가 이렇게 하고 있었다. 비정규화는 이를 피할 수 있게 해준다.

    특별한 발행(Publication)

    우리가 관심있는 댓글 갯수(즉, 현재 우리가 열람중인 post들의 댓글 갯수로 서버에서의 query 모음을 통해 얻는다)만을 내려주는 특별한 publication을 만드는 것이 가능할 수도 있을 것이다.

    하지만, 이것은 그런 발행 코드의 복잡성이 비정규화에 따른 어려움을 초과하지 않을 때에나 고려할 가치가 있다…

    물론, 이러한 고려는 애플리케이션에 따라 달라진다: 만약 데이터의 정합성이 극히 중요한 곳에 코드를 작성한다면, 데이터의 비정합성을 회피하는 것이야 말로 성능상의 이익을 얻는 것보다 훨씬 더 중요하고 더 높은 우선순위를 가지는 것이다.

    도큐먼트를 임베드할 것인가 다중 컬렉션을 사용할 것인가

    Mongo에 경험이 있다면, 댓글에 대한 두 번째 컬렉션을 만든 것에 놀랐을 것이다: 댓글을 post 도큐먼트안에 목록 형태로 임베드하면 어떨까?

    미티어의 많은 도구들이 컬렉션 수준에서 더 잘 작동하는 것이 밝혀졌다. 예를 들면:

    1. {{#each}} 헬퍼는 (collection.find()의 결과) 커서를 따라서 반복할 때 매우 효율적이다. 이것이 큰 도큐먼트에서 객체의 배열을 따라서 반복할 때는 그렇지 않다.
    2. allowdeny는 도큐먼트 수준에서 작동한다. 그리고 이 경우에 개별 댓글을 수정하는 것도 쉽다. 상대적으로 post 수준에서 작동하면 더 복잡하다.
    3. DDP는 도큐먼트의 탑-레벨 속성의 수준에서 작동한다 – 이것은 commentspost의 속성이었다면, post에서 comment가 생성될 때마다 서버가 각 연결된 클라이언트들에게 post에 연결된 comment 목록 전체를 보냈을 것이라는 사실을 의미한다.
    4. 발행과 구독은 도큐먼트 수준에서 제어하기가 훨씬 쉽다. 예를 들어, post의 comment들을 페이징 처리를 하려면, comment가 자체로 컬렉션이 아니라면 매우 어렵다는 것을 알게 될 것이다.

    Mongo에서는 도큐먼트를 가져오는 값비싼 쿼리의 숫자를 줄이기 위해 도큐먼트를 임베딩하는 것을 권한다. 그런데, 이것은 미티어의 구조를 고려할 때 그다지 이슈는 아니다: comments에 대하여 쿼리를 요청하는 대부분의 시간을 클라이언트에서 보낸다. 여기는 데이터베이스 접속이 필연적으로 자유로우니까.

    비정규화의 불리한 점

    데이터를 비정규화해서는 안된다는 좋은 글이 있다. 비정규화에 반대하는 좋은 글로 우리는 Sarah Mei의 Why You Should Never Use MongoDB를 추천한다.