정규화(Normalization)는 관계형 데이터베이스(RDB)의 설계에서
✅ 데이터 중복을 제거하고, ✅ 이상 현상을 방지하고, ✅ 데이터 무결성을 유지하기 위해
정규형에 맞도록 구조화하는 프로세스다.
정규화 과정은 각 관계(relation)가 정규형 기준을 만족하는지 평가하고,
기준을 만족하지 못하면 필요에 따라 관계를 분해한다.

제1정규형(1NF)에서 제4정규형(4NF)로 갈수록 정규화가 더 많이 된다.
이 포스팅에서는 제1정규형,제2정규형, 제3정규형, BCNF의 각 특징을 알아보고,
반대 개념 역정규화에 대해 살펴본다.
제1정규형은 First Normal Form으로 주로 1NF로 부른다.
1NF에서
1. ✅ 테이블의 모든 속성의 값은 원자적이어야 한다.
[1NF를 지키지 않은 경우]

각 부서의 위치를 나타낸 Dlocation 속성에 {Bellaire, Sugarland, Houston}과 같이 여러 값이 배열 형태로 들어있다.
이러한 경우에는 삭제, 업데이트 이상현상(Anomaly) 등이 나타날 수 있다.
한 컬럼에 여러 값이 들어있지만 DB는 컬럼 하나에 들어간 여러 값을 하나의 문자열로 인식하기 때문이다.
'Houston'이라는 하나의 값만 지우고 싶은데 DB에서는 'Bellaire, Sugarland, Houston' 이렇게 하나의 값이므로 개별적으로 데이터를 삭제할 수 없다.
결국 전체 문자열을 덮어씌워야 하는데 불편하고 실수가 일어날 가능성이 커진다.
업데이트하는 경우도 마찬가지이다.
[1NF를 지킨 경우]

Dlocations 컬럼만 따로 DEPT_LOCATIONS 테이블로 따로 분리해서 관계를 생성했다.
DEPARTMENT의 Dnumber라는 PK를 FK로 가지며 연결되고
두 테이블은 모든 컬럼이 원자적이고, 중복되는 행이 없으므로 1NF를 지켰다.
++ 따로 테이블로 분해하지 않고, 각 컬럼의 값이 원자적이도록 개별 행으로 분리하는 방법도 가능하다.
2NF, 3NF, BCNF는 함수적 종속성(funtional dependencies) 개념을 먼저 알아야 한다.
"X -> Y: X functionally determines Y"
함수적 종속성은 X가 Y를 함수적으로 결정한다는 뜻으로 X->Y로 표현한다.
X->Y 관계가 있고
서로 다른 두 튜플이 있을 때,
만약 두 튜플의 X 컬럼의 값이 서로 같다면
Y 컬럼의 값도 같아야 한다.
예를 들어, 출석부 테이블이 있다고 할 때 학번이 같으면 이름과 전공이 같을 것이다.
학번 -> 이름, 학번 -> 전공 관계가 성립한다.
제2정규형의 조건은
1. ✅ 제1정규형을 만족한다.
2. ✅ 모든 컬럼이 완전 함수 종속을 만족한다. (부분 종속성을 제거한다고도 한다.)
"완전 함수 종속"이란,
후보 키 K와 K에 속하지 않는 속성 A가 있을 때, A를 결정하기 위해 K의 일부가 아닌 "K 전체"를 참조해야만 한다는 뜻이다.
예시를 보자.
[2NF를 지키지 않은 경우]

참고로 각 행이 중복되지 않고, 모든 컬럼이 원자적이므로 1NF는 만족했다.
이 테이블의 후보 키는 {종업원, 기술} 세트이다.
그렇다면 완전 함수 종속 정의에 따라
후보 키에 속하지 않는 나머지 속성 {근무지}의 값이 결정되려면
후보 키의 전체 요소 {종업원}, {기술}의 의해 결정되어야 한다.
하지만 현재 이 테이블은 후보 키의 일부분인 {종업원}에만 영향을 받는다.
[2NF를 지킨 경우]

이 테이블을 {종업원} 후보 키를 갖는 "종업원" 테이블과 {종업원, 기술} 후보 키를 갖는 "종업원의 기술" 테이블로 분리하자.
"종업원" 테이블에서 근무지는 유일한 후보키 {종업원}에 의해서 결정되고,
"종업원의 기술" 테이블에서는 후보 키 {종업원, 기술} 외에는 다른 컬럼이 없으니 완전 함수적 종속성을 따른다고 볼 수 있다.
(분해 과정이 은근 재밌는데, 그것까지 하면 포스팅이 너무 길어질 것 같아 다음 포스팅 아이디어로 미룬다..)
이렇게 2NF를 적용하면
제3정규형은
1. ✅ 제2정규형을 만족한다.
2. ✅ 테이블 내의 키가 아닌 모든 컬럼이 테이블의 모든 키에 이행적 종속이 되지 않는다.
"이행적 함수적 종속"이란
어떤 속성 A가 속성 B을 통해 속성 C을 결정하는 경우, A → B → C라면 A → C가 성립하게 되는 상황이다.
C는 B에 의존하고, B는 A에 의존하는 이행 함수적 종속을 제거해야 한다.
[3NF를 지키지 않은 경우]

이 테이블에서 후보 키는 {대회, 연도}이다.
{우승자}는 {대회, 연도}로 결정된다.
{우승자 생년 월일}은 {우승자}에 의해 결정된다.
{대회, 연도}를 알면 우승자를 통해 {우승자 생년 월일}도 알 수 있다.
{대회, 연도} -> {우승자} -> {우승자 생년 월일}로 이어지고
{대회, 연도} -> {우승자 생년 월일}도 성립하는
이행 함수적 종속이 존재한다.
[3NF를 지킨 경우]

"대회 우승자"와 "우승자 생년 월일" 테이블로 분리한다.
이렇게 3NF를 해결하면
보이스-코드 정규형 Boyce-Codd Normal Form는 3NF에서 더 엄격해진 형태로
1. 제3정규형을 만족한다.
2. 모든 함수적 종속이 후보 키에 의해서만 결정되어야 한다.
테이블에 A->B라는 함수적 종속 관계가 있다면
이때 반드시 A는 후보 키여야 한다.
만약 A가 후보 키가 아닌 다른 속성이라면 BCNF를 만족하지 못한다.
데이터 중복을 최소화하기 위한 방법이다.
정규화 과정이란 앞서 말한대로
'각 관계(relation)가 정규형 기준을 만족하는지 평가하고,
기준을 만족하지 못하면 필요에 따라 관계를 분해를 반복하는 과정'이다.
개발 요구사항에 따라
1NF에서 멈출 수도, 2NF에서 멈출 수도 있지만
데이터 중복과 이상 현상을 줄이고 데이터 무결성을 보장하기 위해 분해를 반복하다 보면
처음보다 아주 많은 테이블이 추가로 생길 수 있다.
⚠️ 이 경우 테이블 간 join이 아주 많아져 쿼리 요청을 처리하는 시간이 매우 증가하여
성능이 떨어질 수 있고 많은 테이블을 관리하기 힘들어질 수 있다.
특히, 데이터 조회가 빈번한 "읽기 중심의 시스템"에서는 한 테이블에서 중복된 값들을 가져오는 것보다 여러 테이블을 조인하는 것이 크게 부담이 될 수 있다.
이 상황에는 역정규화를 고려해보자.
데이터 중복 제거, 이상현상 해결, 데이터 무결성 관리를 목표로 정규화를 진행해왔다.
반대로 역정규화를 할 때는 이러한 점들이 크게 문제가 되지 않도록 고려해야 한다.
지금까지의 내용을 토대로 다음과 같이 장단점을 정리할 수 있다.
✅ 장점
⛔ 단점
📕 Fundamentals of Database Systems, 2017, Ramez Elmasri and Shamkant B.Navathe
[Database] 정규화(Normalization)란?
위키백과 제2정규형
위키백과 제3정규형
[DB] 정규화, 역정규화
+데이터베이스 전공 강의와 코드잇 스프린트 강의를 듣고 추가 학습한 내용입니다.