다양한 유형의 검사를 통해 데이터모델을 더욱 명확하게 구조화하고 개선시켜나가는 절차
이커머스에서 상품 관리, 주식 거래 시스템 같이 CRUD가 많이 발생하는 데이터베이스는 데이터의 정합성과 무결성이 매우 중요하므로 정규화가 필요하다.
반대로 분석리포트같이 데이터베이스에서 다수의 조회가 필요하고 join과 caculation이 많이 발생시키는 작업을 수행할 때는 연산속도가 중요하므로, 연산속도 향상을 위해 부분적으로 반정규화(denormalization)을 한다.
주문ID | 주문일 | 회원ID | 회원명 | 회원등급 | 상품ID | 상품명 | 주문량 | 단가 | 구매금액 |
---|---|---|---|---|---|---|---|---|---|
1 | 2020-09-10 | Kim | 김준 | 우수 | A01 | 도마 | 1개 | 20,000 | 20,000 |
1 | 2020-09-10 | Kim | 김준 | 우수 | B01 | 주방칼 | 3개 | 10,000 | 30,000 |
1 | 2020-09-10 | Kim | 김준 | 우수 | C01 | 접시 | 4개 | 5,000 | 20,000 |
2 | 2020-09-11 | Lee | 이수 | 일반 | A01 | 도마 | 2개 | 20,000 | 40,000 |
3 | 2020-09-14 | Park | 박경 | 일반 | C01 | 접시 | 1개 | 5,000 | 5,000 |
3 | 2020-09-14 | Park | 박경 | 일반 | D01 | 행주 | 3개 | 2,000 | 6,000 |
4 | 2020-09-18 | Choi | 최은 | 우수 | B01 | 주방칼 | 2개 | 10,000 | 20,000 |
[그림1] 주문테이블
제 1 정규화 : 복수의 속성값을 갖는 속성을 분리
'그림1'에서와 같이 동일한 성격과 내용의 컬럼이 연속적으로 나타나고 있을 때, 해당 컬럼을 제거하고 기본 테이블의 PK를 추가해 새로운 테이블을 생성하고, 기존의 테이블과 One to many
의 관계를 형성한다.
'그림1'에서는 (같은 주문일임에도)하나의 주문에 여러 상품이 있을 때 주문정보가 계속 중복되기 때문에 주문테이블과 주문상세 테이블로 분리한다.
<주문테이블>
주문ID(PK) | 주문일 | 회원ID | 회원명 | 회원등급 |
---|---|---|---|---|
1 | 2020-09-10 | Kim | 김준 | 우수 |
2 | 2020-09-11 | Lee | 이수 | 일반 |
3 | 2020-09-14 | Park | 박경 | 일반 |
4 | 2020-09-18 | Choi | 최은 | 우수 |
<주문상세테이블>
상품ID(PK) | 주문ID(PK/FK) | 상품명 | 주문량 | 단가 | 최종금액 |
---|---|---|---|---|---|
A01 | 1 | 도마 | 1개 | 20,000 | 20,000 |
A01 | 2 | 도마 | 2개 | 20,000 | 40,000 |
B01 | 1 | 주방칼 | 3개 | 10,000 | 30,000 |
B01 | 4 | 주방칼 | 2개 | 10,000 | 20,000 |
C01 | 1 | 접시 | 4개 | 5,000 | 20,000 |
C01 | 3 | 접시 | 1개 | 5,000 | 5,000 |
D01 | 3 | 행주 | 3개 | 2,000 | 6,000 |
제 2 정규화 : PK가 여러키로 구성된 복합키로 구성된 경우, 복합키 일부분에만 종속되는 속성들을 분리(부분적 함수 종속관계 분리)
주문상세테이블에서 자신의 복합 키 중 '상품ID'에는 의존하지 않기 때문에 이를 상품 테이블로 따로 분리한다.
<주문테이블>
주문ID(PK) | 주문일 | 회원ID | 회원명 | 회원등급 |
---|---|---|---|---|
1 | 2020-09-10 | Kim | 김준 | 우수 |
2 | 2020-09-11 | Lee | 이수 | 일반 |
3 | 2020-09-14 | Park | 박경 | 일반 |
4 | 2020-09-18 | Choi | 최은 | 우수 |
<주문상세테이블>
주문ID(PK/FK) | 상품ID(PK/FK) | 주문량 | 최종금액 |
---|---|---|---|
1 | A01 | 1개 | 20,000 |
1 | B01 | 3개 | 30,000 |
1 | C01 | 4개 | 20,000 |
2 | A01 | 2개 | 40,000 |
3 | C01 | 1개 | 5,000 |
3 | D01 | 3개 | 6,000 |
4 | B01 | 2개 | 20,000 |
<상품테이블>
상품ID(PK) | 상품명 | 단가 |
---|---|---|
A01 | 도마 | 20,000 |
B01 | 주방칼 | 10,000 |
C01 | 접시 | 5,000 |
D01 | 행주 | 2,000 |
제 3 정규화 : 테이블 키가 아닌 컬럼들은 PK에 의존해야 하는데 겉으로 그런것 처럼 보이지만 실제로 기본키가 아닌 일반 컬럼에 의존하는 컬럼들이 있을 수 있다. 이를 이전적 함수 종속 관계라고 한다. 3정규화에서는 PK에 의존하지 않고 일반컬럼에 의존하는 컬럼들을 분리한다.
회원명과 회원등급이 주문ID가 아닌 일반컬럼인 회원ID에 의존하고 있다. 그러므로 분리한다.
<회원테이블>
회원ID(PK) | 회원명 | 회원등급 |
---|---|---|
Kim | 김준 | 우수 |
Lee | 이수 | 일반 |
Park | 박경 | 일반 |
Choi | 최은 | 우수 |
<주문테이블>
주문ID(PK) | 주문일 | 회원ID(FK) |
---|---|---|
1 | 2020-09-10 | Kim |
2 | 2020-09-11 | Lee |
3 | 2020-09-14 | Park |
4 | 2020-09-18 | Choi |
<주문상세테이블>
주문ID(PK/FK) | 상품ID(PK/FK) | 주문량 | 최종금액 |
---|---|---|---|
1 | A01 | 1개 | 20,000 |
1 | B01 | 3개 | 30,000 |
1 | C01 | 4개 | 20,000 |
2 | A01 | 2개 | 40,000 |
3 | C01 | 1개 | 5,000 |
3 | D01 | 3개 | 6,000 |
4 | B01 | 2개 | 20,000 |
<상품테이블>
상품ID(PK) | 상품명 | 단가 |
---|---|---|
A01 | 도마 | 20,000 |
B01 | 주방칼 | 10,000 |
C01 | 접시 | 5,000 |
D01 | 행주 | 2,000 |
예제는 가독성을 위해 상품아이디와 회원아이디 형태를 string으로 구현했지만
실제로는 테이블이 형성될 때 테이블마다 PK용 ID값을 따로 INT로 부여하는것이 좋다. 그래야만 PK값이 중복되지 않고, 1개로 유지되기 때문이다.