테이블 하나에 주문, 고객, 상품 정보를 다 욱여넣었다가 "고객 전화번호를 바꿨는데 어떤 행은 옛날 번호로 남아 있다"는 사고를 겪으면 정규화가 왜 필요한지 체감하게 됩니다. 정규화는 데이터 중복을 줄여 이런 이상 현상(갱신·삽입·삭제 이상)을 막는 설계 규칙입니다. 보통 1NF, 2NF, 3NF까지만 알면 실무 대부분이 해결됩니다.
정규화가 막는 이상 현상
한 테이블에 모든 걸 넣으면 같은 정보가 여러 행에 반복됩니다. 그러면 세 가지 문제가 생깁니다.
| 이상 | 증상 |
|---|---|
| 갱신 이상 | 한 값을 바꿀 때 여러 행을 다 못 고쳐 불일치 발생 |
| 삽입 이상 | 주문이 없으면 상품 정보를 넣을 수 없음 |
| 삭제 이상 | 주문을 지우면 딸려 있던 상품 정보까지 사라짐 |
단계별 정규화
각 단계는 앞 단계를 만족한 상태에서 한 가지 문제를 더 없앱니다.
| 단계 | 없애는 것 | 한 줄 요약 |
|---|---|---|
| 1NF | 반복·다중값 컬럼 | 한 칸에는 값 하나만 |
| 2NF | 부분 함수 종속 | 키 일부에만 의존하는 컬럼 분리 |
| 3NF | 이행 함수 종속 | 키가 아닌 컬럼에 의존하는 컬럼 분리 |
1NF — 한 칸에 값 하나. products 컬럼에 "노트북, 마우스"처럼 여러 값을 콤마로 넣으면 1NF 위반입니다. 한 행당 상품 하나로 펼쳐야 합니다.
2NF — 부분 종속 제거. 기본키가 (주문ID, 상품ID) 복합키인데 상품명이 상품ID에만 의존한다면, 키의 일부에만 매달린 셈입니다. 상품 정보를 별도 products 테이블로 분리합니다.
3NF — 이행 종속 제거. 주문 테이블에 고객ID와 고객등급이 함께 있고, 등급이 사실은 고객에 의해 결정된다면 주문ID → 고객ID → 고객등급이라는 이행 종속이 생깁니다. 고객 정보는 customers 테이블로 빼냅니다.
분리 후 모습
-- 주문은 참조만 들고 있는다
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id),
ordered_at TIMESTAMP
);
CREATE TABLE customers (
customer_id INT PRIMARY KEY,
name TEXT,
grade TEXT -- 고객당 한 곳에만 존재
);
이제 고객 등급을 바꿔도 customers의 한 행만 고치면 됩니다.
무조건 쪼개는 게 답은 아니다
정규화는 일관성을 위한 기본이지만, 조회할 때마다 여러 테이블을 JOIN해야 해서 읽기가 느려질 수 있습니다. 그래서 조회 성능이 중요한 통계·리포트성 테이블에서는 일부러 중복을 허용하는 역정규화(denormalization)를 쓰기도 합니다. 핵심은 "기본은 3NF, 성능 문제가 측정되면 의도적으로 푼다"입니다.
요점 정리
- 정규화는 중복을 줄여 갱신·삽입·삭제 이상을 막는 설계 규칙.
- 1NF=한 칸에 값 하나, 2NF=부분 종속 제거, 3NF=이행 종속 제거.
- 실무는 보통 3NF까지면 충분하고, 성능 필요 시에만 역정규화한다.
실제 주문 테이블을 1NF에서 3NF까지 직접 쪼개보고 이상 현상을 재현·해소하는 실습은 데이터베이스 트랙에서 회원가입 없이 무료로 할 수 있습니다.