고객번호(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정규형에 속한다.
앞서 글에서 정규화를 통해 데이터 중복을 줄이고, 무결성 유지, 저장 공간의 효율적 활용을 가질 수 있음을 설명하였는데, 반정규화가 왜 필요한가? 라고 생각할 수 있다.
하지만 너무 잘게 분리된 테이블은 쿼리 작성 시, 쿼리의 복잡성 증가와 수 많은 테이블 간의 조인 비용이 더 커질 수 있다.
그로 인해 반정규화를 통해 문제를 해결하기 위함.