🎛️정규화 vs 반정규화

2026. 3. 22. 20:03·CS/DB

Intro.

데이터베이스 중 특히 RDB라면 절대 빠질 수 없는 이야기인 정규화에 대해서 얘기해보도록 하겠다. 

 


정규화?

정규화란 쉽게 말해 데이터의 중복을 최소화하고, 무결성을 유지하기 위해 테이블을 쪼개는 과정이다. 그렇다면 왜 굳이 잘 있는 테이블을 쪼개서 복잡하게 만드는 걸까?
 

이상 현상(Anomaly) 방지

만약 정규화를 하지 않고 모든 데이터를 하나의 거대한 테이블에 다 때려 넣으면, 데이터가 중복해서 저장된다. 이 중복은 필연적으로 다음과 같은 이상 현상(Anomaly)을 유발한다.
  • 삽입 이상(Insertion Anomaly): 새 데이터를 넣으려는데, 불필요한 데이터까지 억지로 넣어야 하는 상황. (예: 신입생을 등록하려는데, 아직 수강 신청한 과목이 없어서 '과목명' 컬럼에 NULL을 넣어야만 등록이 가능한 경우)
  • 갱신 이상(Update Anomaly): 중복된 데이터 중 일부만 수정되어 데이터의 일관성이 깨지는 상황. (예: '안상현'의 전공이 바뀌었는데, 3개의 레코드 중 2개만 수정되어 전공이 2개가 되어버린 경우)
  • 삭제 이상(Deletion Anomaly): 특정 데이터를 지웠더니, 지우면 안 되는 유용한 정보까지 함께 날아가는 연쇄 삭제 현상. (예: 수강 취소를 위해 과목 데이터를 지웠더니, 학생의 기본 정보까지 통째로 날아간 경우)

 

정규화가 성능을 저하시킨다?
흔히 정규화를 하면 조인(JOIN)이 많아져서 성능이 떨어진다고만 생각하기 쉽다. 반은 맞고 반은 틀린 이야기다. 정규화는 조회(SELECT) 성능을 일부 희생하는 대신, 쓰기(Insert, Update, Delete - CUD) 성능을 극대화하는 작업이다.
 
데이터가 중복 저장되어 있다면, 한 번의 Update로 끝날 일이 100번, 1000번의 Update로 변질된다. 예를 들어 '컴퓨터공학과'의 사무실 위치가 바뀌었다고 치자. 정규화가 안 된 테이블에서는 컴퓨터공학과 학생 1,000명의 레코드를 모두 찾아서 사무실 위치를 수정해야 한다. 하지만 정규화되어 '학과 테이블'이 분리되어 있다면? 단 한 줄의 레코드만 Update하면 끝난다.
 
또한, 중복 데이터가 사라지면 테이블의 전체 크기가 줄어든다. 이는 디스크 I/O를 줄이고 DB 버퍼 캐시(메모리)의 효율을 높여, 결과적으로 시스템 전반의 성능 향상에 기여하게 된다.
 

정규화(Normalization) 상세 과정

 

제1 정규화 (1NF): 원자성 확보

  • 모든 컬럼의 값은 쪼갤 수 없는 단일 값(원자값)이어야 한다.
학생명
수강과목
안상현
데이터베이스, 운영체제
김철수
자료구조
위 테이블에서 '안상현'의 수강 과목은 두 개가 쉼표로 이어져 있다. 이는 1차 정규형 위반이다. 이를 해결하려면 행을 나누어야 한다.
 
학생명
수강과목
안상현
데이터베이스
안상현
운영체제
김철수
자료구조
 

 

제2 정규화 (2NF): 부분 함수 종속 제거

  • 기본키(PK)가 복합키일 때, 일반 컬럼은 PK 전체에 종속되어야지, PK의 일부에만 종속되면 안 된다.
학생번호(PK)
과목코드(PK)
성적
과목명
101
CS01
A
데이터베이스
101
CS02
B
운영체제
여기서 PK는 (학생번호, 과목코드)다. '성적'은 학생과 과목을 모두 알아야 결정되지만, '과목명'은 '과목코드' 하나만 알아도 결정된다. 즉, 과목명은 PK의 일부에만 종속되어 있다(부분 함수 종속). 이를 분리해야 한다.
 
[수강 테이블]
학생번호(PK)
과목코드(PK)
성적
101
CS01
A
101
CS02
B
 
[과목 테이블]
과목코드(PK)
과목명
CS01
데이터베이스
CS02
운영체제
 

제3 정규화 (3NF): 이행 함수 종속 제거

  • 일반 컬럼끼리 종속 관계가 있으면 안 된다. (A -> B 이고 B -> C 일 때, A -> C 가 되는 현상 제거)
학생번호(PK)
소속단대
단대위치
101
공과대학
제1공학관
102
인문대학
인문관
'학생번호'를 알면 '소속단대'를 알 수 있고, '소속단대'를 알면 '단대위치'를 알 수 있다. 결국 일반 컬럼인 '소속단대'가 '단대위치'를 결정하고 있는 상황이다. 이 역시 테이블을 쪼개야 한다.

 

[학생 테이블]

학생번호(PK)
소속단대
101
공과대학
102
인문대학
 
[단대 테이블]
소속단대(PK)
단대위치
공과대학
제1공학관
인문대학
인문관
 

BCNF (Boyce-Codd Normal Form)

  • 테이블의 모든 결정자(Determinant)가 후보키(Candidate Key)여야 한다
3차 정규화를 만족하더라도 이상 현상이 발생할 수 있는 특수한 경우를 해결하기 위한 단계다.
예를 들어, (학생, 과목)이 기본키(PK)이고 교수라는 일반 컬럼이 있는 수강 테이블을 생각해 보자.
 

 

  • 규칙 1: 한 학생은 특정 과목을 한 명의 교수에게만 듣는다. (학생, 과목 -> 교수)
  • 규칙 2: 한 교수는 하나의 과목만 가르친다. (교수 -> 과목)
학생(PK)
과목(PK)
교수
안상현
데이터베이스
김철수
안상현
운영체제
이영희
박지민
데이터베이스
김철수
 
여기서 '교수'는 일반 컬럼이지만, 규칙 2에 의해 '과목'을 결정하는 결정자 역할을 하고 있다. 그런데 '교수'는 후보키가 아니다. 만약 '김철수' 교수가 가르치는 과목이 '데이터베이스'에서 '자료구조'로 바뀐다면? 안상현과 박지민의 레코드를 모두 찾아 수정해야 하는 갱신 이상이 발생한다.
 
이를 해결하기 위해 BCNF를 적용하여 테이블을 분리한다.
 
[학생-교수 테이블]
학생(PK)
교수(PK)
안상현
김철수
안상현
이영희
박지민
김철수
 
[교수-과목 테이블]
교수(PK)
과목
김철수
데이터베이스
이영희
운영체제
이 외에도 4차(다치 종속 제거), 5차(조인 종속 제거) 정규화가 있지만, 실무에서는 보통 3NF나 BCNF까지만 진행하는 것이 일반적이다. 너무 잘게 쪼개면 조인(JOIN) 비용이 감당할 수 없이 커지기 때문이다.
 

언제 쓸까?

그렇다면 정규화는 언제, 어느 수준까지 진행해야 할까? 정답은 "데이터베이스 설계 초기 단계에서, 최소 3NF(제3정규형) 또는 BCNF 수준까지는 기본적으로 수행해야 한다"이다. 초기 설계 단계에서 정규화를 제대로 해 두지 않으면, 서비스가 커질수록 데이터 정합성이 깨지고 겉잡을 수 없는 버그들이 터져 나온다.

 성능 최적화(반정규화 등)는 나중에 쿼리 튜닝이나 인덱스로 어느 정도 커버할 수 있지만, 한 번 꼬여버린 데이터 구조를 서비스 운영 도중에 뜯어고치는 것은 뼈를 깎는 고통이 수반된다. 따라서 "일단 정규화를 원칙대로 빡세게 하고, 성능 문제가 발생하면 그때 가서 타협(반정규화)한다"는 마인드셋으로 간다.

반정규화(Denormalization)

정규화는 데이터의 무결성을 지키는 훌륭한 정석이다. 하지만 정규화를 거칠수록 테이블은 잘게 쪼개지고, 우리가 원하는 데이터를 한 번에 보려면 수많은 테이블을 JOIN해야 한다. JOIN은 DB에 매우 무겁고 비싼 연산이다.
 
사용자가 게시판 목록을 볼 때마다 게시글 테이블 JOIN, 유저 테이블 JOIN, 카테고리 테이블 JOIN, 댓글 수 테이블을 연산하고 있다면? 서버는 비명을 지르고 사용자는 로딩 창만 쳐다보게 될 것이다.
 
이때 등장하는 구원투수가 바로 반정규화(Denormalization)다. 반정규화는 조회(SELECT) 성능을 극대화하기 위해, 데이터 중복의 위험을 감수하고 의도적으로 정규화 원칙을 위배하여 테이블을 합치거나 중복 컬럼을 추가하는 기법이다.
 

언제 반정규화를 선택해야 할까?

반정규화는 데이터의 일관성을 깨뜨릴 위험이 있으므로 최후의 보루로 남겨두어야 한다. 다음과 같은 상황에서 신중하게 고려해 볼 수 있다.
  1. 조인 비용이 너무 클 때: 자주 조회되는 화면인데, 매번 3~4개 이상의 테이블을 조인해야 해서 성능이 안 나올 때.
  2. 집계 데이터가 자주 필요할 때: '게시글의 총 댓글 수', '유저의 총 결제 금액' 같은 데이터를 매번 SUM()이나 COUNT()로 계산하기 벅찰 때, 아예 부모 테이블에 '댓글 수' 컬럼을 추가해 버리는 방식.
  3. 데이터 변경(CUD)보다 조회(R)가 압도적으로 많을 때: 데이터가 한 번 쓰이면 거의 수정되지 않고 읽히기만 하는 통계성 데이터나 로그성 데이터의 경우.
정규화가 '데이터를 얼마나 깨끗하게 보관할 것인가'에 대한 고민이라면, 반정규화는 '데이터를 얼마나 빠르게 꺼내 쓸 것인가'에 대한 현실적인 타협이다. 교과서적인 정규화에만 얽매이지 않고, 서비스의 트래픽과 비즈니스 요구사항을 분석하여 정석과 변칙 사이에서 최적의 밸런스를 찾아내야 한다. 

'CS > DB' 카테고리의 다른 글

🗂️인덱스, 넌 누구니?  (0) 2026.03.22
📱트랜잭션과 ACID  (0) 2026.03.22
📦RDB와 NoSQL  (0) 2026.03.22
'CS/DB' 카테고리의 다른 글
  • 🗂️인덱스, 넌 누구니?
  • 📱트랜잭션과 ACID
  • 📦RDB와 NoSQL
asht1124
asht1124
DEV blog
  • asht1124
    ASHT
    asht1124
  • 전체
    오늘
    어제
    • 분류 전체보기 (18)
      • 프런트엔드 (0)
      • 백엔드 (0)
        • Sping (0)
      • Dev-ops (0)
      • CS (18)
        • Web 이론 (2)
        • 보안 (1)
        • DB (4)
        • 네트워크 (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    비밀키
    rdb
    3NF
    인터페이스
    BCNF
    API
    정규화
    2NF
    REST API
    RESTful API
    스레드
    PCB
    http
    멀티 스레드
    프로토콜
    acid
    4-way handshake
    멀티 프로세스
    rest
    OAS
    nosql
    3-way handshake
    tcp
    보안
    비대칭키
    tcb
    프로세스
    1NF
    데이터 무결성
    반정규화
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
asht1124
🎛️정규화 vs 반정규화
상단으로

티스토리툴바