조인 비용을 줄이려고 일부러 중복을 두는 것입니다. 읽기가 훨씬 많을 때 쓰고, 대신 갱신할 곳이 여러 군데로 늘어납니다.
반정규화 (Denormalization)
핵심 개념
정규화된 테이블을 성능을 위해 의도적으로 중복시키는 것.
[정규화 상태]
orders: id, user_id, total
users: id, name
→ 주문 조회 시 항상 JOIN 필요
SELECT o.*, u.name
FROM orders o
JOIN users u ON o.user_id = u.id
[반정규화 후]
orders: id, user_id, user_name, total
↑ 중복 저장!
→ JOIN 없이 바로 조회
SELECT * FROM orders WHERE id = 1
정규화 vs 반정규화
항목
정규화
반정규화
중복
없음
의도적 중복
쓰기
빠름
느림 (여러 곳 업데이트)
읽기
느림 (JOIN)
빠름 (JOIN 제거)
정합성
보장
불일치 위험
적합
OLTP (쓰기 중심)
OLAP (읽기 중심)
반정규화 기법
1. 컬럼 추가 (가장 흔함)
orders에 user_name 추가
2. 파생 컬럼 추가
users에 order_count 추가
(매번 COUNT 쿼리 대신)
3. 테이블 병합
1:1 관계 테이블 합치기
4. 요약 테이블
daily_sales 집계 테이블 별도 생성
실무 적용 사례
반정규화가 적합한 경우
- 대시보드 집계 (일별 매출)
- 검색 결과 목록 (JOIN 제거)
- 읽기 비율 >> 쓰기 비율
반정규화를 피해야 할 경우
- 자주 변경되는 데이터
- 정합성이 중요한 금융 데이터
- 쓰기가 많은 시스템
정합성 유지 방법
방법
설명
트리거
원본 변경 시 자동 동기화
이벤트 기반
변경 이벤트 → 비동기 업데이트
배치 처리
주기적 동기화 (집계 테이블)
면접에서 이렇게 나옵니다
Q.반정규화는 언제 필요하고, 어떤 위험이 있나요?
조회 성능이 병목이고 정규화된 구조로는 감당이 안 될 때입니다. 다만 정합성 유지 비용을 함께 집니다.
언제
예
조인이 많아 조회가 느리다
게시글 목록에 작성자 이름을 함께 둔다
집계를 매번 계산하기 비싸다
댓글 수를 컬럼으로 둔다
읽기가 쓰기보다 압도적으로 많다
대시보드, 상품 목록
위험
내용
갱신 이상
원본이 바뀌었는데 사본이 그대로 남는다
갱신 비용 증가
한 값을 고치려고 여러 곳을 고쳐야 한다
코드 복잡도
어디를 함께 고쳐야 하는지 사람이 기억해야 한다
흔한 실수: 측정 없이 미리 반정규화하는 것. 실행 계획을 보고 조인이 실제 병목인지 확인한 뒤에 해야 합니다. 인덱스로 해결되는 경우가 훨씬 많습니다.
Q.반정규화 후 데이터 정합성은 어떻게 유지하나요?
사본을 언제 어떻게 갱신할지 정하고, 어긋남을 감지할 장치를 둡니다.
방법
내용
특징
같은 트랜잭션에서 함께 갱신
원본과 사본을 한 번에
정확하지만 쓰기가 무거워진다
변경 이벤트로 갱신
원본 변경을 구독해 사본을 고친다
결합이 낮다. 잠깐 어긋난다
DB 트리거
DB 가 자동으로 사본을 고친다
코드에 안 보여 추적이 어렵다
주기적 재계산
배치로 다시 맞춘다
그 사이 어긋난 채로 남는다
무엇을 쓰든 정합성 점검을 정기적으로 돌리는 것이 안전합니다. 원본과 사본을 비교해 다른 건수를 알림으로 보내면 조용히 틀어지는 것을 막습니다.
흔한 실수: 갱신 경로를 하나로 가정하는 것. 관리자 화면, 배치, 데이터 보정 스크립트처럼 사본을 모르는 경로가 늘 생깁니다. 그래서 감지 장치가 필요합니다.
Q.읽기 성능 최적화를 위해 반정규화 외에 어떤 방법이 있나요?
반정규화는 정합성 비용이 크므로 대개 마지막에 봅니다.
방법
언제
인덱스 추가와 정비
대부분의 느린 조회가 여기서 해결된다
커버링 인덱스
테이블 접근을 없앤다
쿼리 재작성
함수 적용 제거, 불필요한 조인 제거, 페이지네이션 방식 변경
캐시
반복 조회가 많고 약간의 지연을 허용할 때
읽기 복제본
조회 트래픽을 분산한다
구체화 뷰
집계를 미리 계산해 둔다
파티셔닝
큰 테이블에서 스캔 범위를 줄인다
순서가 있습니다. 먼저 재보고, 인덱스와 쿼리로 풀리는지 확인한 뒤, 캐시와 복제본을 검토하고, 그래도 안 되면 구조를 바꿉니다.
흔한 실수: 캐시부터 붙이는 것. 원인이 풀 스캔이면 캐시가 미스일 때 그대로 느리고, 무효화 문제까지 새로 떠안습니다.