← 개인 공부 · Database
STUDY NOTE · 개념 정리

DB 정규화 정리: 이상 현상, 1NF~BCNF, 반정규화

Database
정규화는 한 테이블에 여러 사실이 섞여서 생기는 이상 현상을 없애려고 테이블을 나누는 과정이다. 기준은 함수 종속성이다. 너무 나누면 조인이 늘어나니, 읽기 성능 때문에 일부러 합치는 반정규화도 같이 알아야 한다.

1. 왜 필요한가: 이상 현상(Anomaly)

학번이름학과학과 사무실과목성적
1김컴공공학관 301DBA
1김컴공공학관 301네트워크B
2이경영경영관 101DBB
이상예시
삽입 이상아직 수강생이 없는 새 학과는 학과 사무실을 넣을 수 없다 (과목이 비어서)
갱신 이상컴공 사무실이 바뀌면 모든 행을 고쳐야 하고, 하나라도 빠뜨리면 데이터가 어긋난다
삭제 이상이 학생이 DB 수강을 취소해 행을 지우면 경영학과 사무실 정보까지 사라진다

원인은 '학생', '학과', '수강'이라는 서로 다른 사실이 한 테이블에 들어 있다는 것이다.

2. 함수 종속성 (Functional Dependency)

X → Y: X 값이 정해지면 Y 값이 하나로 정해진다. (학번 → 이름, 학과 → 학과 사무실)

용어의미
완전 함수 종속기본키 전체에 종속 ({학번, 과목} → 성적)
부분 함수 종속기본키 일부에만 종속 ({학번, 과목} 중 학번 → 이름)
이행 함수 종속A → B, B → C 이므로 A → C (학번 → 학과 → 학과 사무실)
결정자화살표 왼쪽에 오는 속성

3. 정규형 단계

정규형조건위 예시에서 하는 일
1NF모든 값이 더 쪼갤 수 없는 원자값 (한 칸에 여러 값 금지)'과목: DB, 네트워크'처럼 한 칸에 넣지 않고 행으로 나눔
2NF1NF + 부분 함수 종속 제거학번에만 종속된 이름·학과를 학생 테이블로 분리
3NF2NF + 이행 함수 종속 제거학과 → 학과 사무실을 학과 테이블로 분리
BCNF모든 결정자가 후보키아래 예시 참고
4NF다치 종속 제거서로 무관한 다중 값(취미, 자격증)을 한 테이블에 두지 않기
5NF조인 종속 제거실무에서는 거의 다루지 않음

결과:

테이블컬럼
학생학번(PK), 이름, 학과코드(FK)
학과학과코드(PK), 학과명, 학과 사무실
수강학번(FK), 과목(FK), 성적 / PK = {학번, 과목}

외워 두기 좋은 문장: "키에, 키 전체에, 키 말고는 아무것에도 종속되지 않게" (1NF, 2NF, 3NF).

4. 3NF와 BCNF의 차이

수강 테이블 {학생, 과목, 교수}에서 '교수 한 명은 한 과목만 가르친다'면 교수 → 과목이다. 기본키 {학생, 과목}에 대해 부분·이행 종속은 없어서 3NF지만, 결정자인 '교수'가 후보키가 아니므로 BCNF는 아니다. 교수가 담당 과목을 바꾸면 여러 행을 고쳐야 하는 갱신 이상이 남는다. {학생, 교수}와 {교수, 과목}으로 나누면 BCNF가 된다.

3NF는 '키가 아닌 속성'끼리의 종속만 보고, BCNF는 키 일부가 다른 속성에 종속되는 경우까지 막는다고 보면 된다.

5. 반정규화 (Denormalization)

정규화를 많이 할수록 데이터 중복은 줄지만 조회 때 조인이 늘어난다. 읽기가 압도적으로 많고 조인 비용이 문제가 되면, 일관성을 관리할 방법을 정해 두고 일부러 중복을 허용한다.

기법예시대가
계산 값 저장게시글에 댓글 수 컬럼댓글 추가·삭제 때 같이 갱신해야 함
중복 컬럼주문 테이블에 주문 당시 상품명·가격 저장사실 이건 '당시 값'이라는 별개의 사실이라 정규화 위반이 아님
테이블 합치기1:1 관계 테이블을 하나로쓰지 않는 컬럼이 많아질 수 있음
요약 테이블일별 매출 집계 테이블원본과 집계가 어긋나지 않게 배치·트리거 필요

6. 정리

  1. 이상 현상(삽입·갱신·삭제)은 여러 사실이 한 테이블에 섞여서 생긴다.
  2. 1NF 원자값 → 2NF 부분 종속 제거 → 3NF 이행 종속 제거 → BCNF 모든 결정자가 후보키.
  3. 실무 기본 목표는 3NF(또는 BCNF), 그다음 측정해 보고 필요한 곳만 반정규화.
  4. 반정규화는 '중복을 어떻게 맞출지'까지 정해야 끝난다.
Gunmo Lee
DB 정규화 정리: 이상 현상, 1NF~BCNF, 반정규화 | Gunmo's Dev Life