[데이터베이스/DB] 정규화에 대해서(1) - 이상(Anomaly)과 함수적 종속성(FD)
kindof
·2021. 9. 15. 00:11
0. 오버뷰(Overview)
관계형 데이터베이스에서 설계 시 중복을 최소화하기 위해 데이터를 구조화하는 작업을 정규화(Normalization)라고 합니다.
정규화가 왜 필요한지에 대해 이야기하기 위해서, 아래 간단한 예시를 보겠습니다.
학번 | 이름 | 단과대학 | 과목코드 | 중간 성적 |
2016000001 | 조성현 | 공과대학 | CSE123 | A |
2016000002 | 김영희 | 상경대학 | CSE124 | B |
2016000001 | 조성현 | 공과대학 | CSE125 | C |
2016000003 | 이철수 | 문과대학 | CSE126 | F |
위 표는 학번, 이름, 단과대학, 과목, 중간 성적을 저장하고 있는 하나의 데이터베이스 스키마입니다. 그리고 학번과 과목코드가 기본 키(Primary Key)로 역할을 하고 있습니다. 학번과 과목코드를 통해 중간 성적을 결정지을 수 있죠.
하지만 이 표에는 여러 문제점이 있는데요. 어떤 것들이 있을까요?
1) 아직 수업을 하나도 수강하지 않은 학생이 있다고 해봅시다. 현재 KEY를 학번과 과목코드로 지정해 놓았고 기본키로 쓰이는 컬럼은 NULL이 될 수 없으므로 그 학생은 이 테이블에 추가 될 수가 없겠죠. 굳이 삽입하려면 ‘미수강’ 같은 과목코드를 새로 만들어서 삽입해야 합니다.
2) 조성현 학생이 공과대학에서 상경대학으로 전과한다면 위에 저장된 모든 공과대학은 상경대학으로 변경되어야합니다. 그런데 만약 어떤 실수로 인해서 공과대학 하나가 그대로 남아있게 된다면, 이 테이블을 봤을 때 조성현 학생이 공과대학인지 상경대학인지 헷갈리지 않을까요?
3) 조성현 학생이 CSE125 중간 성적이 C라는 것을 알고 철회를 했습니다. 그러면 위 테이블에서 해당 릴레이션 전체를 날려야합니다.
1), 2), 3)에서 말씀드린 내용이 바로 정규화를 제대로 하지 않았을 때 나타날 수 있는 문제점이자 아래서 살펴 볼 이상(Anomaly)에 관한 내용입니다. "어 뭔가 이상한데? 할 때 쓰는 이상과 비슷한 느낌으로 받아들이면 될 것 같습니다."
그래서 정규화는 이런 이상 현상을 방지하고 저장 공간을 효율적으로 사용하기 위해 필요한 개념으로 이해하면 될 것 같습니다.
1. 이상(Anomaly)
위에서 이상(Anomaly)의 종류 세 가지에 대헤 잠깐 이야기해보았는데요. 이상(Anomaly)은 결국 하나의 릴레이션에 많은 속성들이 존재함으로 인해 중복/종속으로 발생하는 문제점이라고 볼 수 있습니다.
- 삽입 이상(Insertion anomalies): 원하지 않는 자료가 삽입되거나 삽입하는 데 자료가 부족해서 삽입이 되지 않는 문제
- 수정 이상(Modification anomalies): 정확하지 않거나 일부의 튜플만 갱신되어 정보가 모호해지거나 일관성이 없어져 정보 파악이 되지 않는 문제
- 삭제 이상(Deletion anomalies): 하나의 자료만 삭제하고 싶지만, 그 자료가 포함된 튜플 전체가 삭제됨으로 원하지 않는 정보 손실이 발생하는 문제
그렇다면 정규화가 이러한 이상 현상을 어떻게 해결하는 걸까요? 그리고 이러한 이상 현상이 일어날지 안 일어날지 어떻게 예측할 수 있을까요?
2. 함수적 종속(Functional Dependency)을 왜 알아야할까?
정규화는 나쁜 릴레이션의 속성(Anomaly를 만들 것 같은)들을 나누어서 더 좋은 형태의 작은 릴레이션으로 분해하는 작업입니다. 이 때, 정규형이란 특정 조건을 만족하는 릴레이션의 스키마 형태를 말하며 제 1 정규형, 제 2 정규형, 제 3 정규형, BCNF 정규형 등이 있죠.
그리고 우리는 엔티티를 구성하고 있는 속성 간에 함수적 종속성(Functional Dependency, FD)를 판단하여 위의 정규형을 만드는 기준, 과정으로 삼게 됩니다.
함수적 종속성이란 속성 데이터들의 의미와 속성들 간의 상호 관계로부터 유도되는 제약조건의 일종입니다. X, Y를 임의의 속성 집합이라고 할 때, X의 값이 Y의 값을 유일하게 결정하면 "X는 Y를 함수적으로 결정한다"라고 하죠. 함수적 종속성은 실세계에 존재하는 속성들 사이의 제약조건으로부터 유도됩니다. 예를 들어 'A를 통해 B를 조회할 수 있어'라고 하면 "A는 B를 함수적으로 결정해야 하는 것이죠.
함수적 종속에는 여러 가지 종류가 있는데 아래 릴레이션을 보면서 설명해보겠습니다.
위 릴레이션에서 우리는 '학번'을 통해 '이름', '나이', '성별'을 고유하게 판별할 수 있습니다. 이 때 이름, 나이, 성별을 종속자라고 하며, 학번을 결정자라고 합니다. 그리고 이름, 나이, 성별은 학번에 함수적인 종속관계가 있다고 말합니다. 이를 기호로 표현하면 아래와 같습니다.
학번 → 이름, 학번 → 나이, 학번 → 성별
1) 완전 함수적 종속(Full Functional Dependency)
완전 함수적 종속이란, 종속자가 기본키에만 종속되며 기본키가 여러 속성으로 구성된 경우 기본키를 구성하는 모든 속성이 포함된 키본키의 부분집합에 종속된 경우입니다. 말이 굉장히 장황하죠? 아래 예시를 보겠습니다.
위 릴레이션에서 기본키는 '고객ID'와 '상품코드'입니다. 여기서 '수량'은 기본키를 구성하는 '고객ID'와 '상품코드' 둘 다를 알아야 식별 가능합니다. 따라서 수량은 완전 함수 종속된 관계라고 합니다.
2) 부분 함수적 종속(Partial Functional Dependency)
위에서 완전 함수적 종속을 봤으니, 부분 함수적 종속은 대충 예상이 가시죠?
부분 함수적 종속이란, 릴레이션에서 종속자가 기본키가 아닌 다른 속성에 종속되거나, 기본키가 여러 속성으로 구성되어 있을 경우 기본키를 구성하는 속성 중 일부만 종속되는 경우입니다.
기본키가 '고객ID'와 '제품코드' 속성으로 구성된 위의 릴레이션에서 '주문상품'은 기본키 중 '제품코드'만 알아도 식별할 수 있습니다. 이 경우에는 '주문상품' 속성은 기본키에 부분 함수 종속된 관계라고 하죠.
3) 이행적 함수 종속(Transitive Functional Dependency)
릴레이션에서 X, Y, Z라는 3 개의 속성이 있을 때 X→Y, Y→Z 이란 종속 관계가 있을 경우, X→Z가 성립될 때 이행적 함수 종속이라고 합니다. 즉, X를 알면 Y를 알고 그를 통해 Z를 알 수 있는 경우를 말합니다.
이 릴레이션에서 '회원번호'를 알면 '이름'을 알 수 있고, '이름'을 알면 '나이'도 알 수 있습니다. 따라서 '회원번호'를 알면 '나이'를 알 수 있으므로 이행적 함수 종속 관계입니다.
지금까지 함수적 종속에 대해 이야기해봤습니다. 그런데 넘어가기 전에 주의할 점 하나만 이야기하려고 합니다.
함수적 종속은 값이 아닌 개념으로 판단해야 한다.
다시 말해, 우리가 위에서 예시로 든 릴레이션이 "딱 저만큼 있는 상황에서 함수적 종속이 이렇게 성립되더라~"가 아니고 "릴레이션이 아무리 확장되거나 축소되어도 각 속성을 보았을 때 개념적으로 함수적 종속이 있을 수밖에 없다"고 판단되어야 합니다.
예를 들어, 가장 마지막 예시에서 나이는 15, 16, 17세로 모두 고유하고 나이를 알면 회원번호를 알 수 있기 때문에 함수적 종속이 있다고 말하면 안 된다는 뜻입니다. 이 후 릴레이션에서 15세라는 나이가 여러 번 등장할 수도 있기 때문이죠!
3. Anomaly, 함수적 종속, 그리고 정규화에 대한 정리
자, 이제 이상(Anomaly)이 무엇인지, 함수적 종속이 무엇인지, 정규화가 무엇인지에 대해 대충 이야기를 해보았습니다.
그러면 지금까지 이야기한 내용을 한 맥락으로 정리해보고 마무리하려고 합니다.
위 테이블에는 세 가지 함수적 종속이 있습니다.
(1) 고객 번호 → 고객 이름: 부분 함수적 종속
(2) {고객 번호, 이벤트 번호} → {고객 이름, 구매한 물품, 당첨 여부}: 완전 함수적 종속
(3) 이벤트 번호 → 당첨 여부: 부분 함수적 종속
그리고 아래와 같은 문제점이 있죠.
1) 중복 문제: 한 릴레이션 안에 {고객 번호, 고객 이름}이 중복되어서 나타납니다.
2) 삽입 이상: 새로운 고객을 추가하고자 하는데, 이 고객은 물건을 산 적이 없습니다. 그러면 위 릴레이션에 고객 데이터를 삽입하기 위해서는 {3, NULL, "조성현", NULL, NULL}을 넣어야겠죠. 하지만 이렇게 되면 이벤트 번호에 NULL이 들어가서 무결성 제약 조건이 깨지게 됩니다.
2) 갱신 이상: 고객 번호 1의 이름을 "홍길동"에서 "원빈"으로 바꾼다고 해봅시다. 그런데 만약 이 고객이 물건을 1000개 샀다면, 우리는 고객 번호 1의 이름을 바꾸기 위해 1000개의 데이터에서 모두 이름을 바꿔줘야 합니다.
3) 삭제 이상: 고객 번호 2가 이벤트 추첨을 했다는 사실을 지운다고 해봅시다. 이를 위해서 이벤트 관련 속성인 {이벤트 번호, 당첨 여부}만 지우고 싶은데 이걸 삭제하게 되면 고객 번호 2에 대한 모든 튜플이 다 날라가게 되죠.
위와 같은 문제가 일어나는 이유가 바로 함수적 종속 중에서 부분 함수적 종속을 포함하고 있기 때문입니다. 따라서 우리는 위와 같은 릴레이션을 분해해서 완전 함수적 종속을 만들 것이고, 그렇게 되면 위와 같은 이상 현상을 없앨 수 있게 됩니다. 다시 말해 {고객 번호, 이벤트 번호}라는 기본키에 모든 속성이 완전 함수 종속이 되도록 만들겠다는 뜻입니다.
사실, 방금 한 이야기는 제 1 정규형의 문제점과 제 2 정규형을 만드는 과정에 대한 이야기였습니다. 하지만 여기서 하고 싶었던 이야기는 하나입니다.
함수적 종속의 문제로 이상(Anomaly)가 생기고, 정규화 과정을 통해 함수 종속성을 수정하여 이상 현상을 해결한다.
다음 포스팅에서 정규화에 대해 이야기해보겠습니다.
'CS > Database' 카테고리의 다른 글
[데이터베이스/DB] 데이터베이스에서 인덱스(INDEX)의 사용 (0) | 2021.11.08 |
---|---|
[데이터베이스/DB] 관계형 DB에서 JOIN의 개념(Inner join과 Left join) (0) | 2021.10.26 |
[데이터베이스/DB] 키(Key)의 종류와 개념 (0) | 2021.09.26 |
[데이터베이스/DB] 정규화에 대해서(2) - 제1,2,3 정규형과 BCNF (0) | 2021.09.15 |