Back to Blog
DBNormalizationFunctional Dependency1NF2NF3NFBCNF

0x07. 정규화 (Normalization)

데이터 중복과 이상 현상을 제거하기 위한 정규화의 원리와 1NF부터 4NF까지의 단계별 과정을 정리한다.

왜 Normalization이 필요한가

데이터베이스를 설계할 때, 하나의 테이블에 여러 종류의 정보를 뒤섞어 넣으면 어떻게 될까? 데이터가 중복되고, 그 중복이 곧 문제를 일으킨다.

중복 데이터가 만드는 문제를 Data Anomaly(데이터 이상 현상)라고 부르며, 크게 세 가지로 나뉜다.

  • Insertion Anomaly: 새로운 레코드를 삽입할 때마다 불필요한 중복 데이터를 함께 넣어야 한다.
  • Deletion Anomaly: 특정 데이터를 삭제하면, 관련된 다른 데이터까지 함께 사라진다.
  • Update Anomaly: 하나의 정보를 수정할 때, 중복된 모든 레코드를 빠짐없이 수정해야 한다. 하나라도 놓치면 데이터 불일치가 발생한다.

이 문제를 해결하는 핵심 아이디어는 Decomposition(분해)이다. 하나의 큰 테이블을 직접적으로 관련된 데이터끼리만 묶어 여러 개의 작은 테이블로 쪼개는 것이다. 이 과정을 Normalization(정규화)이라 한다.

Lossy Decomposition vs. Lossless Decomposition

테이블을 분해할 때 주의할 점이 있다. 분해한 뒤 다시 합쳤을 때 원래 데이터를 복원할 수 있는가이다.

Lossy Decomposition은 분해 후 Join했을 때 원래 Relation을 복원할 수 없는 경우다. Join 결과에 원본에 없던 레코드가 추가로 생겨나면서, 데이터 간의 연결 관계가 사라진다. 이름 그대로 정보가 "손실"되는 분해다.

반면 Lossless Decomposition은 분해한 테이블들을 Join하면 정확히 원래 Relation이 복원되는 분해다. 수식으로 표현하면 다음과 같다.

R1(r)R2(r)=r∏_{R_1}(r) ⋈ ∏_{R_2}(r) = r

Lossy Decomposition의 경우에는 Join 결과가 원본의 상위집합이 된다.

rR1(r)R2(r)r \subset ∏_{R_1}(r) ⋈ ∏_{R_2}(r)

Normalization의 정의와 목표

Database Normalization은 데이터베이스를 구조화하여 데이터 중복을 줄이고 데이터 무결성을 향상시키는 과정이다. 정규화를 통해 얻는 이점은 두 가지로 요약된다.

  1. Relation을 분해하여 Data Anomaly를 억제한다.
  2. 분해가 Lossless임을 보장한다.

Normal Forms

Normalization은 단계적 과정이다. 더 높은 정규형을 달성하려면 이전 단계의 조건을 먼저 만족해야 한다.

1NF → 2NF → 3NF → BCNF → 4NF → ...

각 정규형의 판단 기준이 되는 이론적 배경은 다음과 같다.

  • Functional Dependency (Partial Dependency, Transitive Dependency 포함)
  • Multi-valued Dependency

이 이론들이 특정 Relation이 "좋은 형태(good form)"인지를 판별하는 근거가 된다.

First Normal Form (1NF)

1NF는 가장 기본적인 정규형으로, 다음 조건을 만족해야 한다.

  1. 각 컬럼은 Atomic Value(원자값)만 가져야 한다. INT, FLOAT, CHAR, VARCHAR 등 단일 값이어야 하며, 구조체나 리스트(배열)는 허용되지 않는다.
  2. 각 컬럼의 값은 **동일한 도메인(타입)**에 속해야 한다.
  3. 각 컬럼은 고유한 이름을 가져야 한다.
  4. 데이터가 저장된 순서는 의미가 없어야 한다.
  5. 중복 행이 없어야 한다. Primary Key(PK)가 이를 보장하며, PK에 포함된 속성은 Unique하고 NOT NULL이다.

Functional Dependency

정규화 이론의 핵심 개념인 Functional Dependency(함수적 종속)를 이해해야 한다. 특정 속성 집합의 값이 다른 속성 집합의 값을 유일하게 결정할 때, 함수적 종속이 성립한다. Functional Dependency는 Key 개념의 일반화라고 볼 수 있다.

예를 들어보자.

  • ID instructor (성립) : ID를 알면 해당 교수를 유일하게 식별할 수 있다.
  • ID student (성립)
  • name student (성립하지 않음) : 동명이인이 있을 수 있다.
  • dept_name instructor (성립하지 않음) : 한 학과에 여러 교수가 있다.

간단한 테이블로 살펴보면 다음과 같다.

AB
14
15
37

B의 값은 모두 고유하므로 B A는 성립한다. 반면 A에는 중복 값(1이 두 번)이 있으므로 A B는 성립하지 않는다.

조금 더 실전적인 예시를 보자. in_dep(ID, name, salary, dept_name, building, budget) 릴레이션에서는 다음이 성립한다.

  • dept_name building (성립): 학과명을 알면 건물을 알 수 있다.
  • ID building (성립): ID로 교수를 식별하면 소속 건물을 알 수 있다.
  • dept_name salary (성립하지 않음): 같은 학과에도 연봉이 다른 교수가 있다.

여기서 dept_name과 ID는 각각 Candidate Key가 되며, 이들의 조합인 {ID, dept_name}은 Super Key가 된다.

Second Normal Form (2NF)

2NF의 핵심은 Partial Dependency(부분 종속)가 없어야 한다는 것이다.

Partial Dependency란 무엇인가? PK가 복합키(두 개 이상의 속성으로 구성)일 때, PK의 일부분만으로도 결정되는 Non-PK 속성이 있으면 이를 Partial Dependency라 한다.

쉽게 말하면, PK 전체가 아니라 일부만으로 결정되는 속성이 있으면 2NF 위반이다. 이런 경우 해당 속성을 별도의 테이블로 분리해야 한다.

참고로 PK가 단일 속성인 테이블은 1NF만 만족하면 자동으로 2NF도 만족한다. Partial Dependency 자체가 발생할 수 없기 때문이다.

Third Normal Form (3NF)

3NF는 Transitive Dependency(이행적 종속)가 없어야 한다는 조건을 추가한다.

Transitive Dependency란, PK가 아닌 속성 X가 다른 Non-PK 속성 Y를 결정하는 경우를 말한다. 즉, PK X Y 형태의 종속이 존재하면 Transitive Dependency다.

예를 들어 PK dept_name building 관계가 있다면, building은 PK에 직접 종속되는 것이 아니라 dept_name을 경유해서 종속된다. 이 경우 dept_name과 building을 별도 테이블로 분리해야 3NF를 만족한다.

Boyce-Codd Normal Form (BCNF)

BCNF는 3.5NF라고도 불리며, 3NF보다 더 엄격한 조건을 가진다.

BCNF의 조건은 단순하다. 모든 Functional Dependency A B에 대해, A는 반드시 Super Key여야 한다. 다시 말해, 어떤 속성을 결정하는 결정자(Determinant)는 반드시 Super Key여야 한다는 것이다.

3NF를 만족하는 모든 Relation이 BCNF를 만족하는 것은 아니다. BCNF는 3NF의 부분집합으로, 더 강한 제약 조건을 부여한다.

Fourth Normal Form (4NF)

4NF는 Multi-valued Dependency(다치 종속)가 없어야 한다는 조건을 추가한다.

Multi-valued Dependency는 Relation에 3개 이상의 속성이 있고, A BA C 종속이 동시에 존재하면서 B와 C가 서로 독립적일 때 발생한다.

이 경우 하나의 테이블에 B와 C를 함께 두면 불필요한 조합이 만들어지므로, 별도의 테이블로 분리해야 한다.

Normal Form 요약

정규형 단계를 정리하면 다음과 같다.

정규형핵심 조건
1NFAtomic Value, PK 존재
2NFPartial Dependency 제거
3NFTransitive Dependency 제거
BCNF모든 Determinant가 Super Key
4NFMulti-valued Dependency 제거

Denormalization for Performance

정규화가 항상 정답은 아니다. 정규화를 지나치게 하면 Join 연산이 많아져 조회 성능이 떨어질 수 있다. 이때 고려하는 것이 Denormalization(역정규화)이다.

  • 방법 1: Denormalized Relation 사용 - 조회 속도는 빨라지지만, 저장 공간이 늘어나고 Update 시 추가 비용이 든다. 프로그래머의 추가 작업과 오류 가능성도 증가한다.
  • 방법 2: Materialized View 사용 - 디스크에 저장되는 View를 활용하여 자주 사용하는 Join 결과를 미리 계산해둔다.

Normalization으로 해결되지 않는 문제

정규화만으로 모든 설계 문제가 해결되지는 않는다. 대표적인 예가 시간에 따라 확장되는 데이터다.

잘못된 설계 1: 연도별로 별도 테이블을 만드는 방식

  • earnings_2004(company_id, earnings), earnings_2005(company_id, earnings), ...
  • BCNF를 만족하지만, 연도를 넘나드는 쿼리가 어렵고 매년 새 테이블을 생성해야 한다.

잘못된 설계 2: 연도별 컬럼을 추가하는 방식

  • company_year(company_id, earnings_2004, earnings_2005, earnings_2006)
  • 역시 BCNF를 만족하지만, 매년 새 속성을 추가해야 하며 이것은 Crosstab 형태의 안티패턴이다.

올바른 설계: earnings(company_id, year, amount) - 연도를 속성으로 포함시키면 확장성과 쿼리 편의성 모두 확보된다.


마무리

Normalization은 데이터베이스 설계의 핵심 원칙이다. 데이터 중복을 제거하고 이상 현상을 방지하기 위해 Relation을 체계적으로 분해하는 과정이며, 1NF부터 4NF까지 단계적으로 더 엄격한 조건을 적용한다.

다만 실무에서는 성능을 위해 의도적으로 Denormalization을 적용하는 경우도 있고, 정규화만으로 해결되지 않는 설계 문제도 존재한다. 이론과 실무 사이의 균형을 잡는 것이 좋은 데이터베이스 설계의 핵심이다.

HGU 전산전자공학부 홍참길 교수님의 23-1 Database System 수업을 듣고 작성한 포스트이며, 첨부한 모든 사진은 교수님 수업 PPT의 사진 원본에 필기를 한 수정본입니다.