데이터베이스 설계의 첫걸음은 데이터를 쪼개고 다듬는 '정규화'입니다. 하지만 이론적으로 완벽한 설계가 실무에서는 오히려 성능 저하의 주범이 되기도 합니다. 오늘은 데이터의 무결성을 지키는 정규화와 성능을 위해 원칙을 깨는 반정규화 사이의 균형을 어떻게 잡아야 하는지 알아보겠습니다.
1. 데이터 정규화: 데이터의 중복과 '이상 현상'을 막아라
정규화는 데이터 중복을 제거하여 저장 공간을 효율적으로 사용하고, 데이터의 정합성을 유지하는 과정입니다. 정규화가 안 된 테이블에서는 다음과 같은 이상 현상(Anomaly)이 발생합니다.
- 삽입 이상: 새 데이터를 넣으려는데 불필요한 정보까지 함께 넣어야 하는 상황.
- 삭제 이상: 특정 정보를 지웠는데 원치 않는 다른 정보까지 같이 삭제되는 상황.
- 갱신 이상: 중복된 데이터 중 일부만 수정되어 데이터 불일치가 일어나는 상황.
2. 단계별 정규화 과정 (실전 예시)
① 제1정규화 (1NF): 모든 값은 원자값(하나의 값)이어야 한다
- Before: '수강과목' 컬럼에 [수학, 과학]처럼 여러 값이 들어있음.
- After: 로우(Row)를 분리하여 한 칸에 하나의 과목만 들어가도록 수정.
② 제2정규화 (2NF): 기본키의 일부분에만 의존하는 컬럼을 분리하라
- 대상: 복합키(컬럼 두 개가 합쳐진 PK)를 가진 테이블.
- 예시: [학번 + 과목코드]가 PK인 성적 테이블에 '학생이름'이 있는 경우.
- 학생이름은 '학번'에만 의존하므로, 성적 테이블에서 빼서 별도의 '학생' 테이블로 옮겨야 합니다.
③ 제3정규화 (3NF): 기본키가 아닌 컬럼끼리의 의존 관계를 끊어라
- 설명: 이행적 함수 종속성을 제거하는 단계입니다.
- 예시: [사원번호(PK), 부서코드, 부서명]이 있는 테이블.
- 부서명은 PK가 아닌 '부서코드'에 의존합니다. 따라서 [사원번호, 부서코드] 테이블과 [부서코드, 부서명] 테이블로 분리해야 합니다.
3. 반정규화(Denormalization): 성능을 위한 '의도된' 규칙 위반
정규화를 거치면 테이블이 잘게 쪼개집니다. 데이터를 조회하려면 여러 테이블을 JOIN해야 하는데, 데이터가 수천만 건이라면 조인 비용이 너무 커져서 화면이 멈추는 상황이 발생합니다. 이때 성능을 위해 다시 데이터를 합치는 것이 반정규화입니다.
💡 반정규화의 주요 기법과 예시
1) 컬럼 중복 (가장 흔한 방식)
- 상황: 게시글 목록을 조회할 때마다 '작성자 이름'을 가져오기 위해 '회원' 테이블과 조인해야 함.
- 반정규화: 게시글 테이블에 아예 작성자_이름 컬럼을 추가해버림. 조인 없이 한 번에 조회가 가능해집니다.
2) 통계 컬럼 추가 (파생 컬럼)
- 상황: 특정 주문의 총 결제 금액을 알기 위해 매번 주문상세 테이블의 수천 개 품목을 SUM 해야 함.
- 반정규화: 주문 테이블에 총_결제_금액 컬럼을 미리 만들어두고, 결제 시점에 계산해서 넣어둠.
3) 테이블 분할 (수직/수평 분할)
- 수평 분할(Partitioning): 1억 건의 매출 데이터를 '연도별'로 쪼개서 관리함.
- 수직 분할: 한 테이블에 컬럼이 100개인데, 자주 쓰는 건 5개뿐일 때 테이블을 두 개로 쪼개어 I/O 부하를 줄임.
4. 정규화 vs 반정규화, 무엇을 선택할까?
무턱대고 반정규화를 하면 안 됩니다. 반정규화는 반드시 조회 성능이 임계치를 넘었을 때 최후의 수단으로 고려해야 합니다.
| 구분 | 정규화 (Normalization) | 반정규화 (Denormalization) |
| 목적 | 데이터 무결성, 중복 제거 | 조회 성능 향상, 개발 편의성 |
| 장점 | 데이터 일관성 유지, 유연한 설계 | 조인(Join) 감소로 조회 속도 빠름 |
| 단점 | 테이블 수가 많아져 조인 비용 발생 | 데이터 중복 발생, 수정 시 부하 큼 |
| 적용 시점 | DB 설계 초기 단계 (논리 설계) | 물리 설계 및 성능 테스트 이후 |
🏁 마무리하며: 설계의 정답은 '비즈니스'에 있습니다
이론적으로는 3차 정규화, BCNF까지 마친 설계가 아름답지만, 실제 서비스에서는 사용자에게 1초라도 빨리 결과를 보여주는 것이 더 중요할 때가 많습니다.
- 초기에는 정규화 원칙을 철저히 지켜서 설계하세요.
- 이후 실행 계획을 확인하고 인덱스로도 해결되지 않는 성능 병목이 보일 때,
- 그때 해당 부분만 선택적으로 반정규화를 적용하는 것이 가장 현명한 전략입니다.
'TECH > sql' 카테고리의 다른 글
| [Oracle/PostgreSQL] 뷰(View)가 너무 느리다면? 일반 뷰와 구체화 뷰(Materialized View) 완벽 비교 (0) | 2026.02.27 |
|---|---|
| [SQL 성능 최적화] 서브쿼리 vs 조인: 성능 차이와 상황별 선택 가이드 (EXISTS 활용법 포함) (0) | 2026.02.26 |
| SQL 날짜 더하기/빼기(INTERVAL) - 더 이상 구글링 필요 없는 DB별 문법 총정리 (0) | 2026.02.25 |
| [Database] SQL 성능의 심장: 3가지 조인(Join) 원리 완벽 분석 (NL, Hash, Sort Merge) (1) | 2026.02.25 |
| [SQL] DBMS별 문자열 함수 완벽 비교: SUBSTR, INSTR, 정규표현식(REGEXP) (0) | 2026.02.24 |