정규화 실기 심화 — 1NF → BCNF 단계별 예제
실제 테이블을 1NF → 2NF → 3NF → BCNF로 분해하는 단계별 실기 예제.
실기 단골 서술형. 테이블을 주고 "몇 NF인가?" 또는 "다음 NF로 분해하라"를 묻는다. 각 단계에서 무엇을 제거했는지(원자 값·부분 종속·이행 종속·결정자 비키), 어떻게 분해했는지(PK·FK 배치)를 설명할 수 있어야 한다. 2024년 1·3회차 실기 모두 출제.
정규화 단계는 "무엇을 제거하는가" 순서로 외운다: 1NF=반복 그룹, 2NF=부분 함수 종속, 3NF=이행 함수 종속, BCNF=비키 결정자. 각 단계에서 테이블이 어떻게 쪼개지는지 예제로 익혀야 한다.
| 정규형 | 제거 대상 | 짧은 규칙 |
|---|---|---|
| 1NF | 반복 그룹 | 모든 속성이 원자 값만 가짐 |
| 2NF | 부분 함수 종속 | 1NF + 복합키 전체에 비키 종속 |
| 3NF | 이행 함수 종속 | 2NF + 비키가 비키를 결정 X |
| BCNF | 비키 결정자 | 3NF + 모든 결정자가 후보키 |
| 4NF | 다치 종속 | BCNF + 다치 종속 제거 |
| 5NF | 조인 종속 | 4NF + 무손실 조인 보장 |
단계별 예제 (수강 테이블) 원본: `수강(학번, 과목, 담당교수, 교수전화, 성적)` — PK: (학번, 과목) - 부분 함수 종속: `과목 → 담당교수`, `담당교수 → 교수전화` 존재 - 문제점: 담당교수 변경 시 해당 과목 수강생 전원 갱신 필요 (갱신 이상)
3NF 분해 결과 - `수강(학번, 과목, 성적)` — PK: (학번, 과목) - `과목정보(과목, 담당교수)` — PK: 과목 · FK 없음 (부분 종속 제거 — 2NF) - `교수정보(담당교수, 교수전화)` — PK: 담당교수 (이행 종속 제거 — 3NF) → 한 테이블을 3개로 분리. JOIN으로 원본 복원 가능(무손실).
-- 3NF 분해 후 스키마
CREATE TABLE 수강 (
학번 VARCHAR(10),
과목 VARCHAR(30),
성적 CHAR(2),
PRIMARY KEY (학번, 과목),
FOREIGN KEY (과목) REFERENCES 과목정보(과목)
);
CREATE TABLE 과목정보 (
과목 VARCHAR(30) PRIMARY KEY,
담당교수 VARCHAR(20),
FOREIGN KEY (담당교수) REFERENCES 교수정보(담당교수)
);
CREATE TABLE 교수정보 (
담당교수 VARCHAR(20) PRIMARY KEY,
교수전화 VARCHAR(15)
);원본 수강 테이블을 3개로 분해. 담당교수 변경 시 교수정보 1행만 갱신(정상화). 조회 시 3-way JOIN 필요하지만 이상 현상 제거로 유지보수 비용 하락.
역정규화(Denormalization) — 과도한 JOIN으로 성능이 떨어지면 일부러 정규화를 되돌리는 최적화. DW·OLAP 스키마에서 흔함(스타 스키마의 차원 테이블은 의도적 비정규화). 정규화와 역정규화의 균형이 실무 설계의 핵심.
테이블 `수강(학번, 과목, 담당교수, 교수전화, 성적)`에 `과목 → 담당교수`, `담당교수 → 교수전화` 종속이 있다. 이 테이블은 몇 NF인가?
위 테이블을 3NF로 분해하면 몇 개의 테이블이 생성되는가? 각 테이블의 PK도 함께 쓰시오.
BCNF는 3NF 조건에 더해 "모든 ( ㉠ )가(이) ( ㉡ )여야 한다"는 조건을 추가한다.
정규화를 높은 차수로 진행할수록 JOIN이 증가해 조회 성능이 떨어진다. 이를 완화하기 위해 일부러 비정규화하는 기법을 역정규화라 한다.