데이터베이스 설계의 기본이 되는 개념이 정규화(Normalization)이다.
정규화는 데이터 중복을 줄이고, 이상 현상을 방지하며, 데이터의 일관성과 무결성을 유지하기 위한 테이블 구조 설계 원칙이다.
이 글에서는 1NF → 2NF → 3NF를 직관적인 도식으로 설명하고, 마지막에는 정규화를 언제 하지 않는지(비정규화)까지 정리한다.
1NF는 “각 컬럼의 값이 쪼갤 수 없는 단일 값이어야 한다”는 규칙이다.
학생ID | 이름 | 전화번호
-----------------------------
1 | 민식 | 010-1234-1234, 010-9999-8888
한 셀에 여러 값이 들어가 있으므로 1NF 위반이다.
학생ID | 이름 | 전화번호
-----------------------------
1 | 민식 | 010-1234-1234
1 | 민식 | 010-9999-8888
각 셀은 단일 값(원자값)만 가진다.
2NF는 복합키(Composite Key)에서 발생하는 부분 종속을 제거하는 것이다.
즉, 기본키 전체가 아니라 “일부 PK에만 종속되는 컬럼”이 있으면 위반이다.
PK = (학생ID, 과목ID)
학생ID | 과목ID | 학생이름 | 과목명 | 성적
-----------------------------------------------
1 | 101 | 민식 | 알고리즘 | A
1 | 102 | 민식 | 운영체제 | B
2 | 101 | 영희 | 알고리즘 | B
학생이름 → 학생ID에만 종속됨 과목명 → 과목ID에만 종속됨학생 테이블
students
-------------------------
학생ID(PK) | 학생이름
1 | 민식
2 | 영희
과목 테이블
courses
-------------------------
과목ID(PK) | 과목명
101 | 알고리즘
102 | 운영체제
수강 테이블
enrollment
--------------------------------------------
학생ID(PK, FK) | 과목ID(PK, FK) | 성적
1 | 101 | A
1 | 102 | B
2 | 101 | B
3NF는 일반 컬럼이 다른 일반 컬럼을 결정하는 것을 금지한다.
학생ID(PK) | 학과ID | 학과명
-----------------------------
1 | CS | 컴퓨터공학과
2 | DS | 데이터사이언스학과
문제:
학과 테이블
departments
----------------------------
학과ID(PK) | 학과명
CS | 컴퓨터공학과
DS | 데이터사이언스학과
학생 테이블
students
----------------------------
학생ID(PK) | 학과ID(FK)
1 | CS
2 | DS
=================== 1NF ===================
한 셀에 여러 값 → 안됨
각 셀은 단일 원자값으로 구성해야 함
=================== 2NF ===================
복합키 일부에만 종속된 컬럼 제거
학생이름·과목명처럼 부분 종속 발생 시 분리
=================== 3NF ===================
일반 컬럼이 일반 컬럼을 결정하면 안 됨
학과ID → 학과명 같은 이행적 종속 제거
정규화는 데이터 무결성을 높이는 장점이 있지만, 모든 상황에서 최선은 아니다.
다음 경우에는 의도적으로 정규화를 하지 않기도 한다.
JOIN이 너무 많아지면 조회 성능이 떨어진다.
API 서버에서는 성능을 위해 일부 칼럼을 중복 저장하기도 한다.
예) 주문 테이블에 user_name을 중복 저장
→ JOIN 없이 바로 조회 가능
데이터 웨어하우스나 로그 분석 시스템은 조회 집중형이라
중복이 있어도 무관하다.
Redis, Elasticsearch처럼 한 번에 덩어리로 불러오는 시스템은
정규화를 하지 않는다.
상품 가격, 이벤트명 등은 시간이 지나도 원본값을 그대로 보관해야 한다.
이 경우 중복 저장이 필요하다.
정규화는 데이터 무결성을 지키는 핵심 원칙이지만,
상황에 따라 “정규화를 하지 않는 것(비정규화)”이 성능적으로 더 나을 수 있다.