본문 바로가기

Backend/Database

[Database] 예제로 보는 데이터베이스 정규화

안녕하세요. 오늘 포스팅에서는 데이터베이스의 정규화에 대해 알아보겠습니다.

 

우선 본 포스팅에 앞서 사용한 자료는 이 링크에서 참조하였으며, 유튜브 생활코딩님의 강의를 기반으로 합니다.

 

1. 정규화란?

우선 기본적인 정규화의 의미를 살펴보면, 관계형 데이터베이스의 설계에서 중복을 최소화하게 데이터를 구조화하는 프로세스를 정규화라 합니다. 즉 데이터베이스가 크고 구조화되지 않은 상태라면, 이를 작고 잘 구조화시켜서 저희가 원하는 비즈니스 로직을 수행하는 데에 있어 이상이 없고 효율적으로 처리할 수 있는 데이터베이스 설계를 구축하는 것에 그 목적이 있습니다.

 

여기서 말하는 이상(문제)란 다음과 같습니다.

 

갱신 이상 ( Modification Anomaly )

중복된 데이터 중 일부를 갱신할 때 의도치 않은 데이터가 갱신됨으로써 생기는 데이터의 불일치

삽입 이상 ( Insertion Anomaly )

새 데이터를 삽입할 때 의도치 않은 데이터가 삽입됨으로써 생기는 데이터의 불일치

삭제 이상 ( Deletion Anomaly )

데이터를 삭제할 때 의도치 않은 데이터까지 삭제됨으로써 생기는 데이터의 불

 

즉 위 현상을 해결하기 위해 단계별로 쪼개나가면서 데이터를 작고 구조화시키는 과정으로 이해하시면 됩니다.

 

 

그렇다면 실제 예제로 정규화 과정에 대해 살펴보겠습니다.

 

<Unnormalized Form>

topic                
title type description created author_id author_name author_profile price tag
MySQL paper MySQL is ... 2011 1 kim developer 10000 rdb, free
MySQL online MySQL is ... 2011 1 kim developer 0 rdb, free
ORACLE paper ORACLE is ... 2012 1 kim developer 15000 rdb, commercial

 

우선 위 표를 저희가 데이터베이스에 저장하고 있다고 생각해볼게요. 

 

저희가 topic이라는 테이블에서 tag가 free인 데이터를 원한다고 해보면, 저희는 다음과 같이 query를 작성하고 싶을 것입니다.

 

SELECT * FROM tag WHERE tag='free'

 

하지만 위 쿼리는 만약 데이터베이스가 위 표처럼 만들어져있다면, 당연하게도 처리가 되지 않습니다. 물론 String에서 free값을 갖는 원소만 가져오면 되지! 하시는 분들이 있을 수 있지만, 만약 다음의 쿼리라면 어떻게 될까요?

 

SELECT * FROM tag ORDER BY tag

 

이 경우 rdb의 첫글자를 기준으로 정렬될 수 있지만, 당연하게도 tag에 {free, rdb}이런 식으로 들어가 있을 수도 있고, 저희가 원하는 정렬 상태를 얻기 어려워집니다.

 

여기서 만약에 tag를 기준으로 Join문을 사용한다면 그 문제는 더 커지게되겠죠.

 

여기서 제1 정규화 원칙이 나옵니다.

 

2. 제 1 정규화 Automic Columns

 

하나의 필드에는 하나의 데이터만 들어가야 하며 이를 데이터의 원자성이라고 합니다.

 

위 표를 기준으로 데이터의 중복이 일어나는 Topic의 Tag를 분리시켜줘야 합니다.

 

하나의 Topic은 여러 개의 Tag를 가질수 있고 반대로 하나의 Tag도 여러개의 Topic과 매칭 될 수 있습니다.

이를 관계형 데이터베이스에서는 N대 M 매핑이라고 하고, Spring을 기준으로는 ManyToMany가 됩니다.

 

N대M 매핑에서는 Topic과 Tag를 분리시킨 뒤, Topic과 Tag를 매핑해주는 매핑 테이블을 중간에 하나 두게 됩니다.

 

위 과정을 거친 결과는 다음과 같이 됩니다.

 

topic              
title type description created author_id author_name author_profile price
MySQL paper MySQL is ... 2011 1 kim developer 10000
MySQL online MySQL is ... 2011 1 kim developer 0
ORACLE online ORACLE is ... 2012 1 kim developer 0

 

topic_tag_relation  
topic_title tag_id
MySQL 1
MySQL 2
ORACLE 1
ORACLE 3

 

tag  
id name
1 rdb
2 free
3 commercial

 

이렇게 되면 모든 필드에 대해 하나의 데이터만 받게 됩니다. 이는 1 정규화 원칙을 맞춘 것입니다.

 

3. 제2 정규화 No Partial Dependencies

 

부분 종속성을 해결하자는 게 제2 정규화의 내용입니다. 제1 정규화를 마친 topic 테이블을 다시 한번 가져와 보겠습니다.

 

topic              
title type description created author_id author_name author_profile price
MySQL paper MySQL is ... 2011 1 kim developer 10000
MySQL online MySQL is ... 2011 1 kim developer 0
ORACLE online ORACLE is ... 2012 1 kim developer 0

 

topic에 description, created, author_id, author_name, author_profile이라는 필드들은 모두 MySQL이라는 title에 종속적입니다.

 

조금 자세히 살펴보시면, 저희는 MySQL이라는 title로만 row를 구분할 수 없습니다. 왜냐하면 MySQL이라는 데이터가 중복해서 등장하기 때문입니다.

 

당연하게도 저희가 원하는 Row를 특정 지으려면 MySQL이라는 title, type이 필요합니다.

 

근데 아이러니하게도 description, created, author_id, author_name, author_profile은 저희가 MySQL이라는 title만으로 특정 row를 선택할 수 없음에도 MySQL이라는 title로 확정 지을 수 있습니다. 

 

이를 데이터의 부분적인 종속성(Partial Dependencies)이라 하며 이를 해결하고자 하는 것이 제2 정규화 원칙입니다.

 

즉 특정 Column에 부분적으로 종속적인 데이터를 분리하는 것이 제 2 정규화 원칙입니다.

 

topic          
title description created author_id author_name author_profile
MySQL MySQL is ... 2011 1 kim developer
ORACLE ORACLE is ... 2012 1 kim developer

이렇게 부분 종속적인 데이터만 분리해서 테이블을 하나 만든 뒤,

 

topic_type    
title type price
MySQL paper 10000
MySQL online 0
ORACLE online 0

 

그 외 데이터들만 관리하면, 제2 정규화 원칙에 따라서 데이터를 분리했다고 할 수 있습니다.

 

4. 제3 정규화 No Transitive Dependencies

 

제 3 정규화 원칙은 이행 함수 종속성을 해결하자입니다. 

 

이행 함수 종속성이란 다음과 같습니다.

 

X이기 때문에 Y가 결정되는데, Y이기 때문에 Z가 결정된다고 하면 X이기 때문에 Z가 결정되는 아이러니한 상황이 발생합니다.

 

title description created author_id author_name author_profile
MySQL MySQL is ... 2011 1 kim developer
ORACLE ORACLE is ... 2012 1 kim developer

 

보시면, title이 MySQL이기 때문에 author_id는 1로 고정이 됩니다. 

 

하지만 author_name, author_profile은 author_id가 1이기 때문에 고정됩니다.

 

즉 MySQL이기 때문에 author_id가 1로 고정되고, author_id가 1이기 때문에 author_name과 author_profile이 고정됩니다.

 

이는 다시 말하면 MySQL이면 author_name과 author_profile이 고정되지만, author_id를 한번 거쳐서 고정되기 때문에 이를 분리하고 싶은 것입니다.

 

이렇게 한번 거쳐서 고정되는 것을 이행 함수 종속성(Transitive Dependencies)이라 하며, 이를 해결하고자 하는 것이 제3 정규화입니다.

 

이를 해결하기 위해 author table을 분리합니다.

 

topic      
title description created author_id
MySQL MySQL is ... 2011 1
ORACLE ORACLE is ... 2012 1

 

author    
id author_name author_profile
1 kim developer

 

이렇게 되면 위에서 제기한 이행 함수 종속성을 해결 한 테이블이 만들어지게 됩니다.

 

여기까지 데이터베이스의 1, 2, 3 정규화 원칙에 대해 알아보았습니다.

 

*저의 글에 대한 피드백이나 지적은 언제나 환영합니다.