데이터베이스 설계 중 모델링할 때 가장 중요한 것은 정규화이다. 제1정규화, 제2정규화 등의 용어는 실무에서는 외울 필요는 없고, 결국은 중복데이터를 최소화하는 것이다. 같은 데이터가 여러 테이블에 분산되어있으면 관리하기 어렵기 때문에 중복데이터를 없애고 관계를 단순하게 가져간다.
신입개발자 시절에는 테이블 하나에 데이터를 담는 게 단순한 것인 줄 안다. 그러나 데이터 모델링을 하다 보면, 성격이 다른 데이터는 서로 분리하는 것이 맞다. 이를테면 '학생', '수강신청' 테이블을 하나로 두면 코딩은 쉽겠지만 실제로 데이터베이스는 복잡해진다. 이는 실무에서 해보다보면 스스로 알게 되고, 따라서 이 정규화 과정은 실제로 해보면 몸에 체득이 된다. 무엇인지만 알고 있으면 자연스럽게 된다.
: 원자성
모든 속성은 하나의 값(Atomic Value)만 갖는다.
위 테이블을 보면 추신수, 박세리는 원자성을 준수하지 않는 것을 확인할 수 있다. 이에 1정규화 과정을 거쳐 원자성을 갖도록 분해할 수 있다.
: 완전 함수적 종속 (부분 종속 제거)
모든 속성은 기본키에 종속되어야 한다. 즉, table에 따라 종속되는 column들만 두자는 것.
위와 같은 테이블에서 기본키는 (학생번호, 강좌이름)으로 이루어진 복합키이다.
모든 키는 기본키에 종속되어야 하는데, 값들을 보면 '강의실' 속성의 값들은 '강좌이름'에 의해 결정될 수 있다. 즉, 강좌 이름은 기본키(학생번호, 강좌이름)의 부분키인데, '강의실' 속성은 '강좌 이름'에 종속되어있다는 것이다. 이를 부분 함수적 종속이라고 하는데, 이를 분해하는 것을 2정규화라고 한다.
: 이행 종속 제거
기본키가 아닌 모든 속성 간에는 서로 종속될 수 없다!
정규화는 제4,5,6.. 계속 있지만 가장 주요한 것은 3까지. 그러나 앞으로도 정규화는 필요할 때마다 꾸준히 해나가야 한다.
이행적 종속이라는 것은 A → B, B → C일 때 A → C가 성립되는 것을 의미한다. 예를 들면, 아래의 테이블에서는 '수강료'가 '학생번호' 속성에 이행 종속되어있다고 볼 수 있다.
정규화에서 이행적 종속을 제거해야 하는 이유는 다음과 같이 생각해보면 쉽다. 예를 들어, 402번 학생이 자료구조 수업으로 수강 변경을 하게 되면 수강료도 함께 변경해주어야 하는 번거로움이 생긴다. 이러한 것을 방지하기 위해 제3정규화를 하는 것이다.
제3정규화를 통해 분해한 결과는 다음과 같다.
모든 결정자는 후보키에 속해야 한다.
BCNF 정규화는 모든 결정자가 후보키가 되도록 테이블을 분해하는 것이다.
위 테이블에서 문제는, '교수' 속성은 특강 이름을 결정하는 결정자임에도 후보키가 아니라는 점이다. 이를 후보키로 만들어주면 결과는 다음과 같다.
💡 정규화만이 정답은 아니다!
정규화를 잘 했는데 테이블을 많이 쪼개다보니 성능이 나빠지거나, 비효율성이 발생할 수 있다. 그럴 때에는 반정규화를 한다.
정규화된 데이터 모델을 통합, 중복, 분리하는 과정. 의도적으로 정규화 원칙을 위배하는 것이다.
❗ 데이터 유지 계획 必!!
반정규화는 빅데이터를 다루는, 데이터가 방대한 시스템(ex: 데이터 웨어하우스)에서는 반정규화를 많이 한다. 성능을 위해 반정규화를 한다는 것이다. 단, 한 데이터가 바뀌었을 때 다른 데이터를 어떻게 바꿀 것인지에 대한 데이터 유지 계획이 필수적이다.
고객에 대한 엔티티 타입에 방문을 두 번까지 가능하다고 해보자.
아래 그림을 보면, 고객번호, 고객명이 중복 속성 값을 갖기 때문에 1차 정규화의 대상이 되어 중간에 있는 고객방문 엔티티 타입으로 1차 정규화가 되었다. 그러나 최대 2회까지 방문이 가능하다는 업무 규칙을 이용하여 성능과 단순성을 고려하여 오른쪽에 있는 1차 정규화에 대한 반정규화 엔티티 타입으로 설계된 예이다.
최대 발생하는 값을 이용한 이와 같은 반정규화의 유형은 실전 프로젝트에서 빈번하게 사용되지만, 최대 발생 값이 변할 수 있는 경우는 정규화된 모습으로 모델링해야 확장성(flexible)이 보장된다는 것을 기억해야 한다.
그림의 모델은 일자별 매각 물건 엔티티 타입에서 매각 일자가 결정자가 되고, 매각 장소와 매각 시간이 의존자가 된 함수 종속성이 존재하여 2차 정규화를 적용했다가 다시 조인에 의한 성능저하 예방과 단순성을 위해 다시 일자별매각물건이라는 엔티티 타입에 반정규화를 한 경우이다.
그림을 보면 수납이라고 하는 엔티티 타입은 속성간의 결정자(수납확인번호)와 의존자가 존재하는 3차 정규화의 대상이 되는 모습이다. 따라서 수납확인번호를 결정자로 하고 수납확인방법, 수납확인일자, 수납확인자사번을 속성으로 하는 3차 정규화를 적용하였다.
반정규화를 하는 대상으로는 테이블, 속성, 관계에 대해 적용할 수 있으며 꼭 테이블과 속성, 관계에 대해 중복으로 가져가는 방법만이 반정규화가 아니고 테이블, 속성, 관계를 추가할 수도 있고 분할할 수도 있으며 제거할 수도 있다. 정규화에 위배되는 것은 아니지만 성능을 위해 적용하는 반정규화의 방법으로는 테이블 통합/분리, 속성 중복, 관계 중복 등 여러 가지가 있을 수 있다.
참고 자료