포스트

비정규화 언제 사용되나?

“정규화”, “비정규화”란 용어는 데이터베이스 설계에서 자주 접하게 되는 개념이다. 정규화는 테이블 간 데이터의 중복을 최소화하는 것을 목표로 하며, 이를 통해 데이터 무결성을 유지한다. 반면, 비정규화는 성능 향상, 데이터 검색 속도 증가를 위해 중복, 통합, 분할하는 과정이다.

일반적으로 데이터베이스를 설계할 때, 대부분 정규화를 기본으로 한다. 그리고 그것이 당연하다고 생각했었고 그 외엔 생각하지 못했다. 그러던 중, 한 질문을 받게 되었는데.

비정규화를 사용할 때는 언제인거 같아요?

이 질문은 전혀 생각해보지 못했던 질문이었다. 데이터의 중복을 허용할 때는 언제인걸까? 성능을 더 고려해야 하므로 조인을 줄일 때? 그러면 데이터 중복으로 인해서 수정시 성능 하락이 있지 않을까? 그럼에도 사용할 때가 언제인걸까?

비정규화의 장단점

비정규화는, 앞서 언급했듯이, 데이터 중복을 허용하는 기술이다. 예를 들어, “주문”, “고객” 테이블이 있다고 해보자.

주문 내역과 고객의 이름이 동시에 필요한 상황이라면, 일반적으로는 ‘고객’ 테이블에서 정보를 가져오기 위해 ‘주문’ 테이블과 조인을 수행한다. 이런 조인을 줄이기 위해 ‘주문’ 테이블에 ‘고객 이름’이라는 칼럼을 추가할 수 있다.

이렇게 하면 조회 속도가 빨라질 것이다. 그러나 만약 고객이 이름을 자주 바꾼다면 어떻게 될까?

“고객” 테이블만 수정하는 것이 아니라, “주문” 테이블도 수정해야 할것이다. 이 예시는 단순히 두 개의 테이블에만 해당하지만, 중복이 많은 테이블에서는 이런 문제가 장애로 이어질 수 있다.

denormalization1

출처: https://www.splunk.com/en_us/blog/learn/data-denormalization.html

비정규화의 장점

  • 향상된 쿼리 성능

    데이터베이스가 커질수록, 조인 연산을 통한 성능 저하가 발생한다. 이때 자주 조회되는 데이터를 비정규화하면, 이러한 성능 저하를 방지하고 더 빠른 조회가 가능해진다.

  • 단순한 데이터 모델

    단순한 데이터 모델 데이터를 한 곳에서 관리하고, 조인되는 쿼리의 수를 줄이면, 데이터 모델이 더 단순해진다.

  • 보고서 생성의 효율성

    비정규화를 통해 미리 계산된 값을 저장하면, 사용 통계, 판매 보고서, 집계 등의 보고서를 더 빠르게 생성할 수 있다. 정규화된 상태에서는 이러한 작업을 위해 조인이나 집계 연산을 수행해야 하므로 성능에 영향을 줄 수 있다.

비정규화의 단점

  • 추가 저장 공간

    비정규화의 다양한 기술들은 대체로 추가적인 저장 공간을 필요로 한다.

  • 문서 작업의 필요성

    비정규화는 데이터의 중복을 허용하므로, 데이터 변경에 따른 영향이 다른 곳으로 번질 수 있다. 이를 방지하기 위해 문서 작업을 통해 다른 개발자에게 올바른 정보를 전달해야 한다.

  • 더 많은 코드 작성

    중복된 데이터로 인한 유효성 검증이나 추가적인 코드 작성이 필요할 수 있다.

  • 업데이트 속도 저하

    비정규화는 데이터 검색 속도를 향상시키지만, 반대로 업데이트 속도를 늦츨 수 있다.


비정규화 기술들

비정규화를 하는 방법은 하나만이 아니다. 여러가지 상황이 있고 거기에 맞게 사용할 수 있는 방법들이 있다.

파생되는 값이 자주 사용될 경우

쿼리 실행 중에 반복적으로 계산이 필요한 경우가 있다. 예를 들어, 학생 테이블의 국어, 영어, 수학 점수가 들어있는 테이블이 있다고 해보자.

학생국어영어수학
A908070
B807060
C706050

그런데 선생님이 필요한 값은 학생들의 총점이나 평균이다. 그래서 쿼리를 조회할 때마다 평균 값과 총점을 계산한다. 이때 평균 값과 총점은 파생되는 값이고 자주 사용되기 때문에 비정규화를 통해 같이 저장해보자.

학생국어영어수학총점평균
A90807024080
B80706021070
C70605018060

테이블 사전 조인

테이블을 사전 조인이란, 비즈니스 가치가 없는 테이블에 열을 추가한다. 예를 들어, 카테고리 별로 모든 사용자의 메시지를 조회한다고 해보자. 이때 조인을 줄이기 위해 User_messages 테이블에 category_name 칼럼을 추가한다.

이제 User_messages의 테이블만 조회하면 카테고리별로 분류가 가능해진다. 주의할 점은 카테고리의 이름이 변경되면 User_messages의 칼럼의 이름도 변경해야 한다.

denormalization2

출처: https://rubygarage.org/blog/database-denormalization-with-examples

첨부파일이 여러 개일 때

보통 사용자가 첨부파일을 여러 개 첨부할 때, ‘뻐꾸기 외 3개’처럼 제일 첫 번째 파일 이름만 필요할 때가 있다. 이때 제일 첫 번재 이름만 마스터 테이블에 포함시킨다. 역시나 주의할 점은 파일이 수정될 때, 마스터의 첫 번째 첨부 파일 이름 칼럼도 수정되어야 한다.

denormalization3

테이블 분할

테이블 분할은 큰 테이블을 조금 더 쉽게 쿼리하고 관리할 수 있도록 여러 개의 작은 테이블로 분해하는 프로세스이다.

수평 테이블 분할

수평 테이블 분할이란, 특정 조건에 따라서 을 여러 개의 작은 테이블로 나누는 것의 의미한다. 예를 들어, “고객” 테이블을 가지고 있다고 해보자. 이 테이블은 고객 ID, 이름, 이메일, 거주 지역이 포함된다.

고객이 점차 많아짐에 따라 혹은 요구사항을 위해 거주 지역별로 테이블을 분할하기로 결정했다고 해보자.

고객ID이름이메일거주지
1김철수철수@example.com서울
2이영희영희@example.com부산
3박지성지성@example.com서울
4최수지수지@example.com부산

서울에 거주하는 고객

고객ID이름이메일거주지
1김철수철수@example.com서울
3박지성지성@example.com서울

부산에 거주하는 고객

고객ID이름이메일거주지
2이영희영희@example.com부산
4최수지수지@example.com부산

이렇게 데이터를 분할하면, 특정 지역에 대한 고객 정보를 더 빠르게 검색하고 관리할 수 있게 된다. 단, 전체 고객 데이터를 조회하거나 조인할 때는 성능이 저하될 수 있다. 이때는 뷰를 생성하여 관리하자.

수직 테이블 분할

수직 테이블 분할은 테이블의 을 분할하는 방법이다. 테이블마다 자주 사용되는 칼럼이 있고 반대도 있을것이다. 이때 사용할 수 있는 방법인데. 예를 들어, “사원” 테이블을 가지고 있다고 해보자.

이 테이블에는 사원 ID, 이름, 직무, 이메일이 포함되어 있다. 그런데 사원의 기본 정보만 필요하고 불필요한 이메일 정보는 필요하지 않다고 해보자. 이때 열을 기준으로 테이블을 분할한다.

사원ID이름직무이메일
1김철수개발자철수@example.com
2이영희디자이너영희@example.com
3박지성개발자지성@example.com
4최수지디자이너수지@example.com

사원 기본 정보

사원ID이름
1김철수
2이영희
3박지성
4최수지

사원 이메일 정보

사원ID이메일
1철수@example.com
2영희@example.com
3지성@example.com
4수지@example.com

비정규화를 언제해야 할까?

정규화는 데이터베이스 설계의 핵심 원칙 중 하나이다. 그 이유는 DRY(Don’t Repeat Yourself) 원칙에 따라 중복된 데이터를 피하는 것이 문제를 발생시키는 것을 방지하기 때문이다. 그러나 특정 경우에는 비정규화가 필요할 수 있다.

비정규화를 고려하기 전에 먼저 검토해야 할 몇 가지 핵심 질문이 있다.

  • 잘못 작성된 쿼리나 코드가 있지 않은가? 성능 향상을 위해 쿼리를 수정할 수 있는 여지는 없는지 검토해보자.
  • 인덱스를 통해 성능을 향상시킬 수 있는지 확인해보자.
  • 캐싱을 활용해 성능을 향상시킬 수 있는지 고려해보자.
  • 데이터가 자주 변경되는지 파악하자. 만약 그렇다면, 비정규화는 권장하지 않는다.
  • CQRS(Command Query Responsibility Segregation) 패턴을 적용해 볼 만한 가치가 있는지 고민해보자.

특히, 데이터가 자주 변경되지 않고, 보고서 제출용이 아닌 경우라면, 비정규화가 필요한지 꼼꼼하게 살펴보는 것이 중요하다. 다양한 자료를 통해 얻은 지식으로 보아, 비정규화는 반드시 필요한 경우에만 적용해야 함을 알 수 있었다.




참고 :

https://guides.visual-paradigm.com/balancing-data-integrity-and-performance-normalization-vs-denormalization-in-database-design/

https://www.analyticsvidhya.com/blog/2022/08/database-normalization-a-step-by-step-guide-with-examples/

https://www.splunk.com/en_us/blog/learn/data-denormalization.html

https://rubygarage.org/blog/database-denormalization-with-examples

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.