[DB] 정규화, 반정규화에 대한 고민

3Beom's 개발 블로그·2023년 6월 12일
0
post-thumbnail
post-custom-banner

프로젝트를 진행하면서 정규화와 반정규화에 대해 고민했던 내용을 남겨보려 한다.

프로젝트는 여행 플래너 웹 서비스에 대해 다루었으며, 데이터 중복을 최소화하기 위해 3정규화까지 고려해 테이블을 설계했다.

설계된 테이블 구조는 다음과 같다.

본 서비스에서 제공되는 기능 자체는 많지 않았지만, 테이블을 계속 쪼개고 쪼개다 보니 개수가 늘어나게 되었다.

이렇게 테이블을 쪼개고 개발하면서 느꼈던 점은 다음과 같다.

<좋았던 점>

  1. 데이터 중복을 막을 수 있었다.
  2. 구현되는 기능의 개념이 테이블 구조에도 그대로 녹아있어 체계적이고 구조적인 느낌을 받을 수 있었다. (안정감?)
  3. 테이블 구조에 안정감이 있다보니 데이터 삽입, 수정, 삭제 과정 로직을 짤 때 막힘이 없었다.

<안좋았던 점>

  1. 테이블 간의 관계가 복잡해지다 보니 처음 보는 사람이 구조를 파악할 때 시간이 비교적 오래 걸린다. (그래서 테이블 구조 수정할 때 수정한 내용 무조건 공유해야 한다.)
  2. 쿼리가 길어지고 복잡해진다.
  3. 특정 데이터를 조회할 때, 오직 join 조건만을 위해 여러 개의 테이블들이 탐색되어 지는 경우가 발생한다.
  4. 데이터 삽입, 수정, 삭제 과정 로직 짤 때 막힘은 없었지만, 여러 테이블로 나눠져 있다 보니 까다로워졌다.
  5. 더미데이터 설정할 때 관계도 열심히 고려해야한다.

사실 개발하면서 고생을 좀 하다보니 안좋았던 점이 좀 많아 보이지만(투정이다ㅠ), 데이터 중복이 최소화된다는 점, 기능의 개념이 테이블 구조에 안정적으로 녹아들어 있는 점이 엄청 좋았었다.

개발하면서 안좋았던 점들을 좀 보완할 수 없을까에 대해 고민했었고, 그 내용을 기록해보려 한다.

안좋았던 점이 가장 크게 느껴졌던 테이블 구조는 플랜 데이터를 다루는 테이블들이었다.

먼저 테이블 구조를 설명하자면,

  • 하나의 플랜을 생성할 때, 일자별로 코스를 설정할 수 있다. (1일차, 2일차, ...)
    -> 플랜(plan)은 N개의 일자(days) 데이터를 가질 수 있다.
  • 하나의 일자 내에는 시간 별로 코스를 설정할 수 있다. (1~3시는 해운대, 4~5시는 광안리, ...)
    -> 일자(days)는 N개의 코스(course) 데이터를 가질 수 있다.
  • 각 코스(course)는 하나의 여행지 정보(attraction_info)를 가리키고, 시간 정보를 담고 있다. (start_time, end_time)

위 상황에서 특정 플랜에서 선택된 여행지들의 정보를 얻으려 하면 다음과 같이 join이 이루어진다.

plan -> days -> course -> attraction_info

사실 필요한 데이터는 plan 데이터와 attraction_info 데이터인데 중간에 건너야 하는 다리가 있는 것이다.

본 프로젝트에서는 join 조건이 모두 pk이므로 인덱스가 적용되기도 하고, 테이블 수가 적기도 해서 괜찮을 수 있지만, 찜찜함은 사라지지 않았다.

join 조건에 일반 컬럼이 많이 활용될 경우, 해당 상황에 맞추어 인덱스를 적용해 볼 수 있을 것이다.

하지만 절대적인 테이블 수가 늘어나게 되면 분명 한계가 있을 것이라 생각되었고, 다음과 같이 보완할 수 있을 것이라 생각해 보았다.

<테이블 병합>
만약 테이블 수가 늘어날 경우, 다음과 같이 days 테이블과 course 테이블을 합쳐 테이블 반정규화를 수행할 수 있을 것이다.

이렇게 두 테이블을 합칠 경우, plan 테이블에서 attraction_info 테이블까지 건너가야 하는 다리는 줄어들게 된다.

하지만 테이블에 저장되는 데이터의 중복은 늘어날 것이다.

<테이블 추가>

혹은 다음과 같이 테이블을 추가하는 방식으로도 보완될 수 있다.

특정 plan에 포함되어 있는 여행지 정보들을 모아두는 테이블을 따로 하나 더 생성하는 것이다.

플랜-일자-코스 데이터를 저장하는 구조를 유지하면서 플랜-여행지정보 조회의 이점도 가져올 수 있지만, 사실 똑같은 데이터를 저장하는 또하나의 테이블을 생성하는 것이기 때문에 데이터 중복임에는 변함이 없다.

그리고 만약 이러한 구조가 다른 파트에도 있으면 테이블 수가 쭉쭉 늘어날 것이다.

플랜의 일자, 코스 데이터의 중복을 최소화하면서 플랜과 여행지정보의 조회 성능도 같이 올리고 싶을 경우 테이블을 추가하는 것이 좋을 것 같다.


언급했던 방식들 외에도 개선할 수 있는 수많은 방식들이 있을 것이라 생각된다. 개발하면서 머리가 많이 복잡했는데 그래도 간단하게나마 기록해보니 좀 정리가 되는 느낌이다..!

이번에 진행한 프로젝트의 규모가 크지 않아 고민은 금방 끝났지만, 큰 규모의 프로젝트에 참여하게 될 경우에 대비해서 간단한 것부터 미리 고민하고 결정하는 연습을 해두는게 많은 도움이 되는 것 같다.

profile
경험과 기록으로 성장하기
post-custom-banner

0개의 댓글