| 고객번호(pk) | 영화번호(pk) | 티켓수 | 상영관 |
|---|---|---|---|
| c001 | m002 | 3 | 3관 |
| c004 | m005 | 2 | 2관 |
| c003 | m002 | 5 | 3관 |
| c002 | m001 | 1 | 1관 |
| y001 | m004 | 2 | 5관 |
| c004 | m003 | 1 | 2관 |
| y001 | m002 | 4 | 3관 |
| c003 | m001 | 1 | 1관 |
| c004 | m002 | 2 | 3관 |
삽입 이상 : 데이터 삽입 시, 의도와 상관없이 원하지 않은 값들도 함께 삽입되는 경우
새롭게 출시된 m006이라는 영화가 1관에서 상영된다는 정보를 위 테이블에 Insert 하고자 한다.
그렇다면 <NULL,'m006',NULL,'1관'> 이라는 Tuple이 삽입되어야 하는데, 고객번호가 PK이므로 NULL이 허용되지 않는다.
따라서 해당 데이터를 넣고자 한다면, 임시 값(불필요한 값)이라도 넣어야 Insert 할 수 있다.
갱신 이상 : 속성값을 갱신할 때, 일부 튜플의 정보만 갱신되어 모순이 생기는 경우
m002라는 key값을 가진 영화의 상영관을 3관 -> 1관으로 변경한다고 생각해보자.
위 테이블에서는 4개의 Tuple의 값이 변경되어야 한다.
만약 N개의 Tuple이 있다고 가정한다면, N개의 속성값을 모두 변경시켜야 하는데, 중복된 속성 값 중 일부가 수정되지 않을 경우, 데이터 불일치가 발생할 수 있다.
삭제 이상 : 한 Tuple을 삭제할 때, 의도치 않게 다른 값들도 함께 삭제되는 경우
고객 y001인 고객이 m004영화 예매를 취소한다고 생각해보자.
해당 Tuple을 삭제하게 된다면, m004영화의 상영관 정보를 잃어버리게 된다.
정규화 과정에서 등장하는 함수 종속성에 대해 간단히 살펴보자.
'학번' 이라는 속성의 '이름'을 결정짓는다면, 학번->이름 이라는 함수 종속성이 존재한다.
'학번+과목코드'가 '성적'을 결정짓는다면, '성적'은 '학번+과목코드'에 완전 함수 종속이다.
즉, 성적을 학번과 과목코드의 조합을 통해서만 결정되므로 완전 함수 종속
'학번+과목코드'가 '성적'과'이름'을 결정짓는다면, '이름'은 '학번'에 부분 함수 종속이다.
(학번만으로도 이름을 특정할 수 있기 때문)
A가 B를 결정짓고, B가 C를 결정짓는다면, A가 C를 결정짓는것과 같다.
'학번'이 '전공코드'를 결정하고, '전공코드'가 '전공명'을 결정한다면, 학번->전공명은 이행적 함수 종속이다.
실질적으로 제4정규형 이상은 잘 사용되지 않는다.
각 정규형에 대한 자세한 설명은 새로운 포스팅에서 다루고, 여기서는 각 정규형의 정의만 설명한다.
- 제1정규형 : 어떤 릴레이션 R에 속한 모든 속성의 도메인이 원자 값만을 갖는다면 제1정규형에 속한다.
- 제2정규형 : 어떤 릴레이션 R이 제1정규형이고, 기본키에 속하지 않는 모든 속성이 기본키에 완전 함수 종속이면 제2정규형에 속한다
- 제3정규형 : 어떤 릴레이션 R이 제2정규형이고, 기본키에 속하지 않는 모든 속성이 기본키에 이행적 함수 종속이 아니면 제3정규형에 속한다.
- 보이스코드(BCNF) : 릴레이션 R의 모든 결정자가 후보키이면 릴레이션 R은 보이스코드 정규형에 속한다.
- 제4정규형 : BCNF를 만족하는 릴레이션에 대해서 함수 종속이 아닌 다치종속성을 제거하면 제4정규형에 속한다.
- 제5정규형 : 제4정규형을 만족하는 릴레이션에 대해서 후보키를 통한 조인 종속만 만족된다면 제5정규형에 속한다.
앞서 글에서 정규화를 통해 데이터 중복을 줄이고, 무결성 유지, 저장 공간의 효율적 활용을 가질 수 있음을 설명하였는데, 반정규화가 왜 필요한가? 라고 생각할 수 있다.
하지만 너무 잘게 분리된 테이블은 쿼리 작성 시, 쿼리의 복잡성 증가와 수 많은 테이블 간의 조인 비용이 더 커질 수 있다.
그로 인해 반정규화를 통해 문제를 해결하기 위함.