데이터베이스 설계에서 정규화와 역정규화는 어느 하나가 항상 우월한 선택이 아닙니다. 정규화로 데이터의 기준과 관계를 명확히 만든 뒤, 반복 조회가 집중되는 부분에만 인덱스·캐시·요약 테이블·복제 컬럼을 단계적으로 적용하는 방식이 일반적으로 안정적입니다.
📌 핵심 5줄 요약
1. 정규화는 같은 정보를 여러 곳에 저장하지 않고 테이블과 관계를 분리하는 설계입니다.
2. 역정규화는 조회를 빠르게 하려고 일부 중복 데이터를 의도적으로 허용하는 설계입니다.
3. 정규화의 장점은 수정·삭제·추가 과정에서 데이터 불일치와 이상 현상을 줄이는 데 있습니다.
4. 역정규화의 단점은 변경 지점이 늘어나 동기화 누락, 저장 공간 증가, 갱신 비용이 발생할 수 있다는 점입니다.
5. 실무 원칙은 먼저 정규화하고, 실제 쿼리와 실행 계획으로 병목을 확인한 뒤 필요한 부분만 역정규화하는 것입니다.
📌 목차
01 | 정규화와 역정규화의 기본 개념
02 | 정규화를 사용하는 이유
03 | 정규형은 어디까지 적용할까
04 | 정규화된 테이블의 구조
05 | 정규화에서 생기는 조인 비용
06 | 역정규화의 작동 방식
07 | 역정규화를 고려할 상황
08 | 역정규화의 위험과 관리 방법
09 | 인덱스와 역정규화의 차이
10 | 실행 계획으로 병목 확인하기
11 | 실무 사례로 비교하기
12 | 하이브리드 설계 방법
13 | 설계 후 점검 항목
01 | 정규화와 역정규화의 기본 개념
정규화는 하나의 큰 테이블에 섞여 있는 정보를 의미와 변경 주체에 따라 여러 테이블로 나누고, 기본키와 외래키로 연결하는 과정입니다. 고객 정보, 상품 정보, 주문 정보처럼 서로 다른 속성을 분리해 각 데이터가 한 곳에서 관리되도록 합니다.
역정규화는 정규화된 구조에서 일부 값을 다른 테이블이나 조회용 구조에 다시 저장하는 방법입니다. 예를 들어 주문 상세 화면에서 자주 쓰는 상품명이나 주문 합계를 별도로 보관해 매번 여러 테이블을 조인하지 않도록 할 수 있습니다. 역정규화는 단순한 실수가 아니라 조회 성능이나 서비스 구조를 위해 의도적으로 선택해야 합니다.
02 | 정규화를 사용하는 이유
정규화의 핵심 목적은 중복 데이터와 불일치 가능성을 줄이는 것입니다. 예를 들어 고객 주소를 주문 테이블의 모든 행에 반복 저장하면 주소 변경 시 과거 주문까지 함께 바꿀지, 현재 주소만 바꿀지 판단이 어려워집니다.
고객 테이블에 현재 주소를 한 번만 저장하고 주문에는 고객 식별자만 보관하면 수정 대상이 분명해집니다. 이런 구조는 중복 저장으로 인한 저장 공간 낭비뿐 아니라 추가·수정·삭제 과정에서 발생하는 이상 현상을 줄이는 데 도움이 됩니다.
03 | 정규형은 어디까지 적용할까
기본적인 관계형 설계에서는 제1정규형, 제2정규형, 제3정규형을 기준으로 검토하는 경우가 많습니다. 제1정규형은 한 칸에 여러 값을 넣거나 반복되는 열을 만들지 않는 것이 핵심입니다. 제2정규형은 복합키의 일부에만 종속되는 속성을 분리하고, 제3정규형은 기본키가 아닌 다른 속성에 간접적으로 종속되는 값을 분리하는 방식입니다.
모든 시스템이 가장 엄격한 정규형까지 적용해야 하는 것은 아닙니다. 데이터 변경 빈도, 관계의 복잡도, 조회 방식, 운영 난이도를 함께 고려해야 하며, 정규화 수준을 높인 뒤 실제 쿼리가 지나치게 복잡해지는지 확인해야 합니다.
04 | 정규화된 테이블의 구조
온라인 쇼핑몰의 주문을 예로 들면 다음처럼 분리할 수 있습니다.
| 테이블 | 주요 역할 |
|---|---|
| 고객 | 고객 식별자, 이름, 연락처 등 고객 자체의 정보 저장 |
| 상품 | 상품 식별자, 상품명, 현재 판매 상태 등 상품 정보 저장 |
| 주문 | 주문 식별자, 고객 식별자, 주문일 등 주문 단위 정보 저장 |
| 주문상품 | 주문 식별자, 상품 식별자, 수량, 판매 당시 금액 저장 |
주문상품 테이블에 상품의 현재 카테고리명까지 반복 저장하지 않는다면 상품명이나 카테고리 변경 시 수정 범위를 줄일 수 있습니다. 다만 판매 당시 상품명과 금액처럼 거래 시점의 사실을 보존해야 하는 값은 별도 정책에 따라 주문상품에 저장할 수 있습니다. 이것은 무조건적인 중복이 아니라 이력 보존을 위한 설계 판단입니다.
05 | 정규화에서 생기는 조인 비용
정규화된 구조는 필요한 데이터를 여러 테이블에서 조합해야 하므로 조회 시 조인이 늘어날 수 있습니다. 특히 목록 화면에서 고객명, 상품명, 주문 합계, 배송 상태를 한 번에 보여주면 여러 테이블을 연결하고 집계하는 쿼리가 필요합니다.
하지만 조인이 많다는 사실만으로 정규화가 잘못된 것은 아닙니다. 조인 조건에 적절한 인덱스가 있으면 조인 쿼리도 효율적으로 실행될 수 있습니다. PostgreSQL 문서 역시 조인 조건에 사용되는 열의 인덱스가 조회를 빠르게 하는 데 도움이 될 수 있다고 설명합니다.
06 | 역정규화의 작동 방식
역정규화는 자주 함께 읽는 정보를 같은 테이블이나 별도 조회 구조에 미리 모아두는 방식입니다. 예를 들어 게시글 목록에서 댓글 수와 작성자 표시명을 매번 집계하지 않고 게시글 테이블 또는 요약 테이블에 저장할 수 있습니다.
이렇게 하면 조회 시 필요한 조인이나 집계가 줄어들 수 있지만, 원본 데이터가 바뀔 때 복제된 값도 함께 갱신해야 합니다. 따라서 역정규화 컬럼에는 원본이 무엇인지, 갱신 시점은 언제인지, 불일치가 발생하면 어떻게 복구할지를 정해두어야 합니다.
07 | 역정규화를 고려할 상황
다음과 같은 조건에서는 역정규화를 검토할 수 있습니다.
- 특정 조회가 매우 빈번하고 같은 조인·집계가 반복되는 경우
- 읽기 요청이 쓰기 요청보다 훨씬 많은 서비스인 경우
- 목록 화면이나 검색 결과에서 항상 함께 보여주는 값이 있는 경우
- 대시보드처럼 미리 계산한 합계나 개수가 반복적으로 필요한 경우
- 서로 다른 저장소나 서비스 사이에서 조회용 데이터를 별도로 제공해야 하는 경우
다만 먼저 쿼리 구조, 인덱스, 페이지네이션, 캐시, 집계 방식으로 해결할 수 있는지 확인해야 합니다. 역정규화는 성능 문제의 원인을 확인한 뒤 적용하는 마지막 수단에 가깝습니다.
08 | 역정규화의 위험과 관리 방법
가장 큰 위험은 데이터 불일치입니다. 상품명이 상품 테이블에서는 변경됐지만 주문 목록에 복제된 상품명이 갱신되지 않으면 화면마다 서로 다른 정보가 표시될 수 있습니다.
이를 줄이려면 복제 데이터의 성격을 명확히 해야 합니다. 현재 상태를 보여주는 값이라면 변경 트랜잭션 안에서 함께 갱신할지 검토하고, 통계나 검색용 값이라면 일정 지연을 허용할지 정해야 합니다. 또한 정기적인 대조 작업, 재생성 가능한 배치, 오류 발생 시 재처리 절차를 준비해야 합니다.
09 | 인덱스와 역정규화의 차이
인덱스는 원본 데이터를 중복해서 애플리케이션이 직접 관리하는 것이 아니라, 데이터베이스가 검색과 정렬을 빠르게 수행하도록 돕는 구조입니다. 반면 역정규화는 조회에 필요한 값을 테이블이나 문서에 추가로 저장하는 설계입니다.
따라서 조인 조건이나 검색 조건에 인덱스를 추가하는 것만으로 문제가 해결될 수 있다면 역정규화보다 인덱스를 먼저 검토하는 편이 안전합니다. 단, 인덱스도 저장 공간과 쓰기 비용을 증가시키므로 사용되지 않는 인덱스를 무작정 늘려서는 안 됩니다.
10 | 실행 계획으로 병목 확인하기
성능 개선 전에 실제 쿼리의 실행 계획을 확인해야 합니다. PostgreSQL에서는 EXPLAIN과 EXPLAIN ANALYZE를 사용해 어떤 테이블을 순차 검색하는지, 인덱스를 사용하는지, 조인 방식과 예상 행 수가 실제와 얼마나 다른지 살펴볼 수 있습니다.
확인할 항목은 다음과 같습니다.
- 필터 조건에 맞는 인덱스를 사용하는가
- 조인 대상의 예상 행 수와 실제 행 수에 큰 차이가 있는가
- 불필요하게 많은 행을 읽은 뒤 버리고 있지 않은가
- 정렬·집계·페이지네이션이 병목을 만들고 있는가
- 쿼리 개선 후 실제 응답 시간과 데이터베이스 부하가 줄었는가
실행 계획은 데이터 분포와 통계 정보의 영향을 받으므로 개발 환경의 소량 데이터만 보고 결론을 내리면 안 됩니다. 실제에 가까운 데이터와 대표 쿼리로 측정해야 합니다.
11 | 실무 사례로 비교하기
주문 목록에서 주문별 상품명과 고객명을 보여주는 상황을 생각해 보겠습니다. 정규화 구조에서는 주문, 고객, 주문상품, 상품을 조인해 최신 정보를 조회합니다. 고객명이나 상품명이 변경되면 기준 테이블의 값이 바로 반영되는 장점이 있습니다.
반대로 목록 조회가 매우 빈번하고 변경 이력보다 빠른 표시가 중요하다면 주문 조회용 테이블에 고객 표시명, 대표 상품명, 주문 합계를 저장할 수 있습니다. 이때 상품명 변경 정책, 여러 상품이 포함된 주문의 대표명 기준, 합계 재계산 조건을 함께 정의해야 합니다. 기준 없이 값을 복제하면 조회 속도는 얻어도 운영 중 불일치가 누적될 수 있습니다.
12 | 하이브리드 설계 방법
실무에서는 정규화와 역정규화를 양자택일하기보다 영역별로 섞는 경우가 많습니다. 원본 거래 데이터는 정규화해 정확성과 이력을 보존하고, 검색·목록·통계 화면에는 별도의 읽기 모델이나 요약 데이터를 제공하는 방식입니다.
이 구조에서는 원본과 조회용 데이터의 관계가 분명해야 합니다. 조회용 테이블은 원본에서 다시 만들 수 있도록 설계하고, 이벤트·배치·트리거 등 어떤 방식으로 갱신하는지 문서화해야 합니다. 읽기 모델이 잠시 늦게 반영될 수 있다면 사용자 화면에도 최신성 기준을 명확히 적용해야 합니다.
13 | 설계 후 점검 항목
정규화된 설계라면 테이블 간 관계, 기본키·외래키, 필수값, 유일성 조건이 요구사항을 제대로 표현하는지 확인합니다. 중복이 있다면 그 중복이 실수인지, 이력 보존이나 조회 최적화를 위한 의도인지 구분해야 합니다.
역정규화된 설계라면 원본 데이터, 복제 데이터, 갱신 책임자, 갱신 시점, 실패 시 재처리 방법을 문서화해야 합니다. 특히 집계 값은 원본 행이 추가·수정·삭제될 때 모두 정확히 갱신되는지 테스트해야 합니다.
☑ 체크리스트
다음 질문에 답하면 정규화와 역정규화의 방향을 정하기 쉽습니다.
- 같은 값이 여러 행에 반복 저장되고 있는가
- 그 값이 변경될 때 수정해야 할 위치가 몇 곳인가
- 조회 지연이 실제 사용자 경험이나 업무에 영향을 주는가
- 병목 쿼리와 실행 계획을 측정했는가
- 인덱스·쿼리 수정·캐시로 먼저 해결할 수 있는가
- 복제 값이 원본과 달라졌을 때 탐지하고 복구할 수 있는가
- 데이터가 실시간으로 일치해야 하는지, 일정 지연을 허용하는지 정했는가
📖 자주하는 질문 Q&A
정규화하면 조회 성능이 항상 떨어지나요?
그렇지는 않습니다. 적절한 인덱스와 쿼리 구조를 사용하면 여러 테이블의 조인도 효율적으로 실행될 수 있습니다. 성능 저하는 테이블 개수만으로 판단하지 말고 실제 실행 계획과 응답 시간을 기준으로 확인해야 합니다.
역정규화는 언제 적용하는 것이 좋나요?
특정 조회가 반복되고, 실행 계획에서 조인·집계가 명확한 병목으로 확인되며, 인덱스나 쿼리 개선만으로 충분하지 않을 때 검토하는 것이 좋습니다.
상품명이나 가격을 주문 테이블에 저장하면 중복 아닌가요?
현재 상품 정보를 단순히 복제한 것이라면 중복일 수 있습니다. 그러나 주문 당시 표시된 상품명이나 판매 가격처럼 거래 시점의 사실을 보존하려는 목적이라면 이력 데이터로서 별도 저장이 필요할 수 있습니다.
인덱스와 역정규화 중 무엇을 먼저 해야 하나요?
대부분은 쿼리와 인덱스를 먼저 점검하는 편이 안전합니다. 인덱스가 실제 조건과 조인에 맞는지 확인한 뒤에도 병목이 남고 복제 데이터의 관리 비용을 감당할 수 있을 때 역정규화를 선택합니다.
📝 마무리
정규화는 데이터의 일관성과 변경 안전성을 높이고, 역정규화는 반복 조회의 비용을 줄이는 데 유용합니다. 가장 안전한 순서는 정규화된 모델을 출발점으로 삼고, 실제 쿼리와 실행 계획으로 병목을 확인한 뒤 필요한 부분만 역정규화하는 것입니다.
