개요
데이터 모델링을 하면 무의식적으로 정규화를 합니다. 이를 공식으로 정리한 내용을 배워 개념을 잘 다지기 위해 DB 정규화를 정리합니다.
- 정규화를 왜 해야 할까?
정규화를 무작정 외우기 전에 먼저 정규화를 왜 해야 하는지, 데이터 모델링의 핵심이 무엇인지 고민해야 합니다. DB 데이터 모델링의 핵심은 '중복을 제거' 입니다. 중복을 제거하지 않으면 이상 현상이 발생하고 데이터를 관리할 수 없습니다. 설계할 때 각 테이블의 데이터를 원자(ATOM) 상태로 모두 쪼개서 1:1, 1:M, M:N 관계를 맺습니다. 이 모든 것이 데이터 중복 현상을 방지하기 위해서입니다. 따라서, 어떻게 데이터 무결성을 지키면서 설계할 수 있을지 고민해야 합니다.
제1 정규화
- 모든 속성은 반드시 하나의 값을 가져야 합니다.
- 값은 원자성(ATOM)을 가져야 합니다. 즉, 더 이상 쪼개지지 않는 하나의 값을 가집니다.
- 다가속성
같은 종류의 값을 여러 개 가지는 속성을 의미합니다. 아래 고객번호 1,2는 전화번호를 2개나 가지고 있습니다. 이는 하나의 속성에 값이 2개 이상 부여되어 1정규화를 위반합니다. 또한 고객번호에 따라서 고객명, 주민번호가 결정되지만 전화번호는 2개 이상이므로 1개를 결정할 수 없습니다.
#고객번호 | 고객명 | 주민번호 | 전화번호 |
1 | 안정환 | 12345-6789 | 123-456, 234-567 |
2 | 손흥민 | 67890-1234 | 345-567, 678-876 |
3 | 박지성 | 13579-2468 | 135-246 |
1정규화를 하면 아래와 같습니다.
#고객번호 | 고객명 | 주민번호 | 전화번호 |
1 | 안정환 | 12345-6789 | 123-456 |
1 | 안정환 | 12345-6789 | 234-567 |
2 | 손흥민 | 67890-1234 | 345-567 |
2 | 손흥민 | 67890-1234 | 678-876 |
3 | 박지성 | 13579-2468 | 135-246 |
그러나, 고객번호, 고객명, 주민번호가 똑같은 데이터가 생깁니다. 따라서 다시 테이블을 분리해야 합니다. 하나의 테이블에는 고객번호, 고객명, 주민번호를 남기고 다른 테이블은 고객번호와 전화번호를 남깁니다. 1: M 관계가 됩니다.
#고객번호 | 고객명 | 주민번호 |
1 | 안정환 | 12345-6789 |
2 | 손흥민 | 67890-1234 |
3 | 박지성 | 13579-2468 |
고객번호 | #전화번호 |
1 | 123-456 |
1 | 234-567 |
2 | 345-567 |
2 | 678-876 |
3 | 135-246 |
- 복합속성
값이 원자성(ATOM)을 위반하고 더 작은 단위로 쪼개질 수 있음을 의미합니다. 만약에 프로젝트에 따라 고객명의 성과 이름을 분리해야 하는 경우에는 복합속성을 분리해야 합니다.
#고객번호 | 고객명 | 주민번호 |
1 | 안정환 | 12345-6789 |
2 | 손흥민 | 67890-1234 |
3 | 박지성 | 13579-2468 |
복합속성을 해결하면 아래와 같습니다.
#고객번호 | 성 | 이름 | 주민번호 |
1 | 안 | 정환 | 12345-6789 |
2 | 손 | 흥민 | 67890-1234 |
3 | 박 | 지성 | 13579-2468 |
복합속성 비슷한 예로, 주소를 1개의 속성으로 지정하면 안 되고 시, 도, 군, 읍, 면, 리, 상세주소 등등 나누어야 관리가 편합니다.
- 유사한 속성 반복
같은 개념을 가진 속성이 여러 번 반복됩니다. 1정규형은 속성이 반복되면 안 됩니다. 상품번호와 주문수량 속성이 반복됩니다.
#주문번호 | 고객번호 | 주문일자 | 상품번호1 | 주문수량1 | 상품번호2 | 주문수량2 |
1234 | 21 | 2002 | P1 | 1 | A1 | 4 |
2345 | 22 | 2004 | P2 | 2 | A2 | 5 |
3456 | 23 | 2006 | P1 | 3 | A3 | 6 |
유사한 속성 반복을 해결하면 아래와 같습니다.
#주문번호 | 고객번호 | 주문일자 |
1234 | 21 | 2002 |
2345 | 22 | 2004 |
3456 | 23 | 2006 |
#주문번호 | 상품번호 | 주문일자 |
1234 | P1 | 1 |
1234 | A1 | 4 |
2345 | P2 | 2 |
2345 | A2 | 5 |
3456 | P1 | 3 |
3456 | A3 | 6 |
제 2정규화
- PK가 2개 이상으로 구성되어 있습니다.
- 모든 비 식별자 속성은 후보 식별자 속성에 완전히 종속되어야 합니다.
- 후보 식별자에 종속되지 않는 속성은 기본 엔티티에서 제거하고 결정자를 주 식별자로 하여 새로운 엔티티를 만듭니다
- 왕자와 왕비가 있는데 왕비가 사조직을 키우는 왕족 반란으로 외우자
주문 상품 테이블 예제
주문번호와 상품번호를 PK로 가지는 주문 상품 테이블이 있습니다. PK가 아닌 3개의 칼럼은 상품명, 주문일시, 주문수량입니다. 이 중 상품명은 상품번호에만 단독으로 종속됩니다. 따라서 상품번호를 주 식별자로 하는 새로운 엔티티를 만듭니다.
PK | 주문번호 |
PK | 상품번호 |
상품명 | |
주문수량 | |
단가 |
새로운 구조는 아래와 같습니다. 주문 상품 테이블과 상품 테이블입니다.
PK | 주문번호 |
PK/FK | 상품번호 |
주문수량 |
PK | 상품번호 |
상품명 | |
단가 |
대분류, 소분류 예제
리그명이 PK인 대분류와 소분류에 동시에 종속되고 있을까요? 2개의 PK에 모두 종속되어야 하지만 소분류에만 종속되어 있습니다. 따라서 제2 정규형을 위반하고 있습니다. 테이블을 분리하는 것도 방법이지만, 또 하나의 방법은 리그명을 2개의 PK에 모두 종속되도록 수정하는 것입니다.
#대분류 | #소분류 | 리그명 |
10 | 1001 | 북부 |
10 | 1002 | 남부 |
20 | 2001 | 북부 |
20 | 2002 | 남부 |
대분류가 1부 리그, 2부 리그를 결정하고 소분류는 북부와 남부를 결정합니다. 대분류와 소분류 모두를 이용한 리그명을 수정합니다. 따라서 제2 정규형을 만족한다고 볼 수 있습니다. 참고로 결과는 비즈니스 로직에 따라서 달라집니다. 어떤 경우에는 리그명을 제2 정규형을 위반한다고 볼 수 있습니다. 그렇다면 소분류를 PK, 대분류를 FK로 바꿔서 해결할 수도 있고 소분류와 리그명을 칼럼으로 가지는 새로운 엔티티를 만들어 해결할 수도 있습니다.
#대분류 | #소분류 | 리그명 |
10 | 1001 | 1부리그 북부 |
10 | 1002 | 1부리그 남부 |
20 | 2001 | 2부리그 북부 |
20 | 2002 | 2부리그 남부 |
만약 제2 정규형을 위반한다는 결론이 나왔다면 아래와 같이 별도의 테이블로 분리하고 M : N 관계로 처리합니다. 한 가지 팁은 대분류번호와 소분류 번호를 모두 PK로 만들면 중복을 허용하지 않습니다. 중복을 허용하는 경우 별도의 seq 칼럼을 만들어 PK를 지정하면 됩니다.
제3 정규화
- 식별자가 아닌 속성 간에는 종속성이 존재하지 않습니다.
- 3정규형 대상이 되는 속성을 이행 종속 속성이라고 합니다.
- 종속성 결정자를 식별자로 하는 새로운 엔티티를 만듭니다.
- 왕자와 왕비가 아닌 호족이 주인을 행사하므로 호족의 반란으로 보자
주문 테이블 예제
주문번호를 PK로 하는 주문 테이블이 있습니다. 고객명은 고객번호에 종속됩니다. 고객번호는 PK가 아님에도 특정 속성을 종속하는 이행 종속 속성을 가집니다. 따라서, 고객번호를 PK로 하는 새로운 엔티티를 만들어야 합니다.
PK | 주문번호 |
고객번호 | |
고객명 | |
주문일자 | |
배송요청일자 |
주문 테이블에서 고객명을 제거하고, 고객 테이블을 새로 만들어 고객명을 추가합니다.
PK | 주문번호 |
FK | 고객번호 |
주문일자 | |
배송요청일자 |
PK | 고객번호 |
고객명 |
참고
RDBMS Modeling 기초 - 이교준
'학습 > DB' 카테고리의 다른 글
오라클 조작 명령어 모음(테이블/코멘트/시퀀스/배치) (1) | 2023.10.13 |
---|---|
Oracle에서 NULL처리 (1) | 2023.10.11 |
서브쿼리 의존증 (2) | 2023.04.02 |
UNION을 사용한 쓸데없이 긴 표현 (0) | 2023.04.01 |
sort merge join (0) | 2022.10.10 |