정규화
- DB의 테이블이 잘 만들어졌는지 평가하고, 잘 만들지 못한 테이블을 고쳐나가는 과정
- 테이블을 정규형(NF, normal form)이라고 불리는 형태에 부합하게 만들어감
- 일반적으로 3NF에 부합하는 데이터베이스를 보고 "정규화된 데이터베이스"라고 부름
ex
- 제 n정규형 등으로 부르며, 순서에 따라 규칙이 누적됨
- 대부분의 경우 제 3정규형에 부합하기만 하면 잘 정규화된 DB라고 표현
- 정규화를 하면 DB에서 삽입/업데이트/삭제 이상을 제거할 수 있다
- 새로운 종류의 데이터를 추가할 때 테이블 구조 수정을 많이 하지 않아도 된다
- DB구조의 단순화 > 사용자가 더 쉽게 이해 가능
- 데이터 모델을 만들고 실제 DB에 구현하기 전에 적용하면 좋음 (DB 수정이 번거롭기 때문)
1. 제 1정규형 (1NF)
1NF는 테이블의 모든 로우의 모든 컬럼 값들은 나눌 수 없는 단일 값이어야 한다.
컬럼 수를 늘려 해결할 수 있지만, 위에 기재된것 처럼 문제가 있음 > 1NF에 부합하긴 해도 좋은 모델링은 아님
phone_number 테이블을 따로 만들고 user_id를 외래키로 설정
+
- 1NF를 확대해서 해석 한다면, 컬럼을 늘리는 방법은 1NF를 지킨다고 볼 수 없음
- 이유: 1NF를 지키기 위해서 단순히 테이블의 컬럼을 늘리게 된다면 구조적으로 NULL이 많이 생기게 되는 문제가 발생
>> NULL은 아무 값도 없는, 즉 0개의 값을 저장, 0개는 단일 값, 즉 하나의 값에 해당하지 않음
- 한 컬럼에 같은 종류의 값을 여러 개 저장하고 있을 때 > 해당 컬럼을 하나의 테이블로 분리해서 모델링
- 한 컬럼에 서로 다른 종류의 값을 여러 개 저장하고 있을 때 > 한 컬럼을 여러 개로 분리해서 모델링
2. 함수 종속성(Functioinal Defendecy)
- 테이블 안의 어트리뷰트 사이에서 생기는 관계
x가 3일 때 y는 무조건 4 > y가 x의 값에 대해서 결정될 때 y는 x에 함수 종속성이 있다
y가 1일 때, x의 값은 0/2 이기에 x는 y에 함수 종속성이 없다.
- user의 이메일은 중복될 수 없음 > 하나의 유저를 특정지을 때 사용 가능 > 유저의 이메일을 통해 나머지 값이 결정된다 할 수 있음
>>
name, age, gender는 email에 함수 종속성이 있다. (그 반대는 아님)
score은 user,product_id에 함수 종속성이 있다.
- 함수 종속성에는 이행성이라는 속성이 있다
- 하나 이상의 어트리뷰트를 건너서 함수 종속성이 있는 경우에 함수 종속성이 넘어갔다(이행됐다)라고 표현
>>
brand_country는 product_id에 이행적 함수 종속성이 있다
3. candidate key
- 하나의 로우를 특정지을 수 있는 어트리뷰트들의 최소 집합
- 여러개의 candidate key가 존재할 수 있지만, primary key는 하나만 존재 가능
score 없이 user_id와 product_id 만으로 하나의 로우 특정 가능
- candidate key에 포함된 어트리뷰트는 프라임 어트리뷰트라고 부름
(위 경우 id / user_id / product_id 가 프라임 어트리뷰트)
4. 2NF / 3NF
2NF
2NF를 지키지 않음
candidate key의 일부분에만 의존하는 non-prime attribute들을 따로 분리함
- 옮겨줄 테이블이 없으면 새로운 테이블을 만들어 거기에 저장
3NF
winner -> age (종속성)
- 2NF에 부합하는 테이블
- 3NF에 부합하기 위해선 이러한 이행적 함수 종속성도 존재하면 안됨
>>
새로운 테이블 생성 후 이행적 함수 종속성이 있는 어트리뷰트를 생성한 테이블에 옮기고 그 테이블에 대한 외래키 칼럼을 추가
예제)
1NF
두 테이블 사이의 관계는 M:N 관계 > 연결테이블 필요!
product_keyword 연결테이블 생성
2NF
- 현재 테이블은 1NF에 부합하고 있기 때문에 2NF에 부합하기 위해서는 candidate key의 일부분에만 의존하는 non-prime attribute은 없어야 함
A. 테이블의 candidate key와 non-prime attribute들을 파악
( id는 attribute 하나만으로 모든 상품을 특정지을 수 있기 때문에 생각하지 않고 여러 attribute의 조합으로 만들어지는 candidate key에 대해서만 생각 )
B. 상품 이름 name, 브랜드 이름 brand, 그리고 크기 size, 이 세 attribute이 있으면 하나의 상품을 특정 지을 수 있음
> {name, brand, size} 이게 하나의 candidate key
C. 각 non-prime attribute의 함수 종속성 파악
brand -> brand_country
{name, brand} -> {price, designer, designer_country}
{name, brand, size} -> in_stock
product 테이블을, 모든 non-prime attribute이 candidate key의 전체에만 함수 종속성이 있는 세 개의 테이블로 분리
- 상품은 딱 하나의 브랜드만 가질 수 있음
- 브랜드는 수많은 상품을 가질 수 있음
- brand와 product 사이에는 1:N 관계 > product 테이블에 foreign key를 넣어줘서 관계를 모델링
- 상품은 여러 개의 크기와 재고를 가질 수 있음
- 특정 크기와 재고는 항상 하나의 상품에만 대한 내용
- product와 product_size_stock은 1:N 관계 > product_size_stock 테이블에 foreign key를 넣어줘서 관계를 모델링
3NF
A. 이행적 함수 종속성 파악
(id > designer > designer_nationality)
B. 테이블 분리
- 하나의 상품은 하나의 디자이너에 해당하고, 디자이너는 여러 상품 가능 > 상품과 디자이너는 N:1 관계
- product 테이블에 foreign key를 넣어줘서 관계를 모델링
>> 정규화 과정을 통해 1개의 테이블이 6개로 분리됨
( 중복되는 데이터 등 모델링 실수로 생기는 데이터베이스 이상 현상을 웬만해서는 다 예방할 수 있음 )