정규화(Normalization)
정규화란 무엇인가?
정규화(Normalization)는 데이터베이스의 테이블(릴레이션)을 잘게 분할하고, 각 테이블이 적절한 제약조건(함수적 종속성 등)을 만족하도록 구조화하는 과정을 말합니다. 목표는 크게 두 가지입니다:
- 데이터 중복(Redundancy) 최소화
- 데이터 이상 현상(Anomalies) 방지 및 무결성(Integrity) 보장
중복이 많다면 수정할 때 여러 곳을 동시에 변경해야 하므로 실수를 유발하기 쉽고, 삽입/갱신/삭제 시에도 원치 않는 에러나 데이터 불일치가 발생할 수 있습니다. 따라서 정규화를 통해 안정하고 효율적인 데이터베이스를 구축하는 것이 매우 중요합니다.
정규화를 해야 하는 이유
데이터 중복 최소화
동일한 데이터를 여러 테이블이나 여러 컬럼에 반복해서 저장하면, 수정 시 모든 중복 데이터를 동일하게 갱신해야 합니다. 이를 누락하면 데이터 불일치가 발생합니다.
이상 현상(Anomalies) 방지
- 삽입 이상(Insertion Anomaly) : 새 정보를 넣으려면 불필요한 다른 정보도 함께 입력해야 하거나, 데이터 구조상 제약으로 인해 삽입이 곤란해지는 상황
- 갱신 이상(Update Anomaly) : 중복된 정보가 여러 곳에 존재해, 일부만 수정될 경우 데이터가 일관성을 잃어버리는 상황
- 삭제 이상(Deletion Anomaly) : 특정 정보를 삭제하면, 그 정보와 관계없는 데이터까지 같이 사라져버리는 상황
데이터 무결성(Integrity) 보장
테이블 간 참조 무결성(Foreign Key) 및 속성값의 일관성을 확실하게 유지할 수 있습니다.
테이블 구조 명확화
테이블 설계가 명료해지며, 유지보수 시에도 구조를 이해하기가 훨씬 용이해집니다.
정규화의 기초 개념
함수적 종속성(Functional Dependency)
어떤 속성(또는 속성 집합) X에 의해 다른 속성 Y가 유일하게 결정되는 관계를 말합니다. "X > Y"라고 표현하며, 이는 "X 값을 알면 Y 값을 정확히 결정할 수 있다"는 의미입니다.
예시:
- "학번 > 이름, 학과" : 학번만 알면 그 학생이 누구이고 어떤 학과인지 정확히 알 수 있음
키(Key)의 종류
- 후보 키(Candidate Key) : 튜플(행)을 유일하게 식별할 수 있는 최소 속성(집합)
- 기본 키(Primary Key) : 후보 키 중 대표로 선정된 키
- 대체 키(Alternate Key) : 후보 키 중 기본 키로 선정되지 않은 나머지 키
- 외래 키(Foreign Key) : 다른 테이블의 기본 키(또는 후보 키)를 참조하는 속성
정규화 단계별 특징
정규화는 일반적으로 1NF > 2NF > 3NF > BCNF > 4NF > 5NF 순으로 나아갑니다. 실무에서 자주 적용되는 것은 3NF나 BCNF 정도까지이며, 4NF 이상은 특수한 경우에 한해 적용하는 경우가 많습니다.
제1정규형(1NF)
모든 속성은 원자값(Atomic Value)을 가져야 합니다.
한 컬럼에 여러 값을 넣거나(예: `홍길동,김영희`), 반복되는 그룹을 두면 안됩니다.
예시:
- (비정규) `전화번호` 컬럼에 여러 개의 번호를 콤마로 구분해 넣음
- (정규) `전화번호`를 별도 테이블로 분리하거나, 다중 컬럼(핸드폰번호, 집전화번호 등)으로 분리
제2정규형(2NF)
1NF를 만족하면서, 부분 함수 종속(Partial Dependency)을 제거해야 합니다.
부분 종속이란, 복합 키(둘 이상의 속성으로 이루어진 기본 키)의 일부만으로 다른 속성이 결정되는 것을 의미합니다.
예시:
- 주문 테이블에서 (주문번호, 상품번호)가 기본 키라고 할 때, `상품명`은 사실 상품번호만으로도 알 수 있습니다. 이는 (주문번호, 상품번호) 중 상품번호만으로 결정되는 부분 함수 종속이므로 상품 정보를 별도 테이블로 분리해야 합니다.
제3정규형(3NF)
2NF를 만족하면서, 이행적 함수 종속(Transitive Dependency)을 제거해야 합니다.
이행적 종속이란 기본 키가 아닌 다른 속성이 또 다른 속성을 결정하는 관계(기본 키 > A > B)를 말합니다.
예시:
- 학생 테이블에서 `학번(PK) > 학과 > 학과전화번호` 같은 구조가 있다면, 학과 전화번호는 학번이 아니라 학과에 종속된 것입니다. 이런 속성들은 별도의 학과 테이블로 분리해 이행 종속을 없앱니다.
BCNF (Boyce-Codd Normal Form)
결정자(어떤 속성을 결정하는 주체)가 모두 후보 키(Candidate Key)여야 하는 더욱 엄격한 조건을 요구합니다.
3NF에서는 기본 키가 아닌 속성 간 종속을 주로 다루지만, BCNF는 모든 결정자가 오직 후보 키여야 한다는 점에서 더 엄격합니다.
제4정규형(4NF)
BCNF를 만족하면서, 다치 종속(Multi-Valued Dependency)을 제거해야 합니다.
한 속성이 여러 값(스킬, 프로젝트 등)을 가질 수 있고, 이 값들이 상호 독립적이라면 테이블을 별도로 분리해 중복을 제거합니다.
제5정규형(5NF)
4NF를 만족하고, 조인 종속(Join Dependency)을 완전히 분해한 상태입니다.
여러 테이블을 조인했을 때 원래의 테이블로 정확히 복원되면서, 불필요한 속성 중복이 없는 최종 단계이지만, 실무에서는 극히 복잡한 상황이 아니면 잘 적용되지 않습니다.
간단 예시: 주문 테이블 정규화
예를 들어, 아래와 같은 주문 테이블이 있다고 가정해보겠습니다.
주문번호(PK) | 고객명 | 고객주소 | 상품번호(PK) | 상품명 | 단가 | 수량 |
1001 | 김철수 | 서울 강남구 | A101 | 노트북 | 100 | 2 |
1002 | 김영희 | 서울 강동구 | A102 | 마우스 | 10 | 1 |
1003 | 김영희 | 서울 강동구 | A103 | 키보드 | 20 | 1 |
1004 | 이민수 | 서울 서초구 | A101 | 노트북 | 100 | 1 |
- (주문번호, 상품번호)가 기본 키일 때, `고객명`, `고객주소`는 주문번호만으로 결정되고, `상품명`, `단가`는 상품번호만으로 결정됩니다.
- 이는 부분 함수 종속이므로, 다음과 같은 테이블 구조로 분리할 수 있습니다.
- 주문(Orders) : 주문번호(PK), 고객ID(FK), 주문일, 총금액 등
- 주문 상세(OrderDetails) : 주문번호(FK, PK), 상품번호(FK, PK), 수량, 단가 등
- 고객(Customers) : 고객ID(PK), 고객명, 고객주소 등
- 상품(Products) : 상품번호(PK), 상품명, 단가, 재고수량 등
이렇게 구조화하면 중복이 제거되고, 고객정보/상품정보가 바뀌어도 해당 테이블만 수정하면 됩니다.
정규화의 장단점
장점
- 데이터 중복 최소화 : 저장공간 절약, 갱신 시 일관성 유지
- 이상 현상 감소 : 삽입·수정·삭제 시 오류나 불필요 데이터 누락 가능성 감소
- 데이터 구조 명확화 : 유지보수 및 확장에 용이
- 무결성(Integrity) 향상 : 잘못된 데이터가 삽입·갱신될 확률이 줄어듦
단점
- 테이블 분할 증가 → 조회할 때 조인(Join) 연산이 많아져 성능 저하를 유발할 수도 있음
- 과도한 정규화는 오히려 설계나 쿼리 구조를 복잡하게 만들 수 있음
- 실무에서는 일부러 조인을 줄이기 위해 역정규화(De-Normalization) 기법을 적용하기도 합니다.
역정규화(De-Normalization)란?
정규화를 통해 테이블이 나뉘면, SELECT 시 여러 테이블을 조인해야 하므로 성능이 저하되는 문제가 생길 수 있습니다.
이때 조인 횟수를 줄이고 조회 속도를 높이기 위해, 의도적으로 중복을 허용하는 기법이 “역정규화”입니다.
- 예시: 자주 조회되는 고객명, 상품명을 주문 상세 테이블에 캐싱(중복)해두어, 주문 상세만 조회해도 고객·상품 정보를 알 수 있게 하는 경우
- 단, 중복된 데이터를 어떻게 동기화하고 무결성을 지킬 것인지가 관건입니다.