반정규화

임지원·2026년 1월 4일

반정규화 (Denormalization)

개요

반정규화는 정규화된 데이터베이스 구조에서 성능 향상이나 특정 목적을 위해 의도적으로 정규화 규칙을 완화하는 데이터베이스 설계 기법입니다.


반정규화의 목적

1. 성능 최적화

  • JOIN 연산 감소: 여러 테이블을 조인하는 대신 하나의 테이블에서 데이터를 조회
  • 쿼리 속도 향상: 자주 조회되는 데이터를 중복 저장하여 조회 시간 단축
  • 읽기 성능 개선: 읽기 중심의 애플리케이션에서 특히 효과적

2. 비즈니스 요구사항 충족

  • 보고서 생성 최적화: 복잡한 집계 쿼리 대신 미리 계산된 값 저장
  • 실시간 통계: 자주 변경되는 통계 데이터를 별도 컬럼으로 관리
  • 데이터 접근 패턴 반영: 실제 사용 패턴에 맞춘 데이터 구조 설계

정규화 vs 반정규화

구분정규화반정규화
목적데이터 중복 제거, 무결성 보장성능 향상, 조회 속도 개선
데이터 중복최소화의도적 중복 허용
저장 공간효율적상대적으로 비효율적
데이터 일관성높음낮음 (관리 필요)
업데이트 비용낮음높음 (여러 곳 수정 필요)
조회 성능상대적으로 느림 (JOIN 필요)빠름 (단일 테이블 조회)

반정규화 기법

1. 컬럼 추가 (Column Addition)

설명: 다른 테이블의 데이터를 현재 테이블에 중복 저장

예시:

-- 정규화된 구조
Orders 테이블: order_id, customer_id, order_date
Customers 테이블: customer_id, customer_name, customer_email

-- 반정규화: Orders 테이블에 customer_name 추가
Orders 테이블: order_id, customer_id, customer_name, order_date

장점: 주문 조회 시 JOIN 없이 고객명 바로 조회 가능
단점: 고객명 변경 시 Orders 테이블도 업데이트 필요


2. 테이블 병합 (Table Merging)

설명: 자주 함께 조회되는 테이블을 하나로 합침

예시:

-- 정규화된 구조
Users 테이블: user_id, username, email
UserProfiles 테이블: user_id, address, phone, birth_date

-- 반정규화: 두 테이블 병합
Users 테이블: user_id, username, email, address, phone, birth_date

장점: 사용자 정보 조회 시 JOIN 불필요
단점: NULL 값 증가 가능, 테이블 크기 증가


3. 파생 컬럼 추가 (Derived Column)

설명: 계산된 값을 미리 저장하여 조회 시 계산 비용 절감

예시:

-- 정규화된 구조
OrderItems 테이블: order_id, product_id, quantity, unit_price
-- 총액은 매번 계산: SUM(quantity * unit_price)

-- 반정규화: 총액 컬럼 추가
Orders 테이블: order_id, customer_id, total_amount, order_date

장점: 집계 쿼리 성능 향상
단점: OrderItems 변경 시 Orders.total_amount도 업데이트 필요


4. 중복 테이블 생성 (Duplicated Table)

설명: 동일한 데이터를 다른 구조로 저장하여 다양한 조회 패턴 지원

예시:

-- 원본 테이블 (정규화)
Transactions: transaction_id, user_id, amount, created_at

-- 반정규화: 보고서용 테이블
DailyReports: date, user_id, total_amount, transaction_count

장점: 보고서 생성 속도 향상
단점: 데이터 동기화 로직 필요, 저장 공간 증가


5. 집계 테이블 (Summary Table)

설명: 자주 조회되는 집계 데이터를 미리 계산하여 저장

예시:

-- 반정규화: 집계 테이블
ProductStats: 
  product_id, 
  total_sales, 
  average_rating, 
  review_count,
  last_updated

장점: 복잡한 집계 쿼리 대신 단순 SELECT로 조회
단점: 원본 데이터 변경 시 집계 테이블 갱신 필요


반정규화 시 고려사항

1. 데이터 일관성 관리

  • 트리거 활용: 원본 데이터 변경 시 자동으로 반정규화된 데이터 업데이트
  • 애플리케이션 로직: 업데이트 시 관련된 모든 반정규화 데이터 동기화
  • 배치 작업: 주기적으로 데이터 일관성 검증 및 수정

2. 업데이트 비용 증가

  • 여러 테이블에 동일한 데이터가 존재하므로 업데이트 시 여러 곳 수정 필요
  • 트랜잭션 범위가 넓어질 수 있음

3. 저장 공간 증가

  • 데이터 중복으로 인한 저장 공간 증가
  • 대용량 데이터의 경우 비용 증가 가능

4. 복잡도 증가

  • 데이터 모델이 복잡해져 유지보수 어려움
  • 새로운 개발자 온보딩 시간 증가

반정규화 적용 시나리오

적합한 경우

  • 읽기 중심 애플리케이션: 조회가 업데이트보다 훨씬 많은 경우
  • 복잡한 JOIN 쿼리: 자주 실행되는 복잡한 JOIN이 성능 병목인 경우
  • 보고서 생성: 대용량 데이터 집계가 필요한 경우
  • 실시간 통계: 실시간으로 집계 데이터가 필요한 경우
  • 읽기 성능이 중요: 마이크로초 단위 성능이 중요한 경우

부적합한 경우

  • 쓰기 중심 애플리케이션: 업데이트가 빈번한 경우
  • 데이터 일관성이 중요: 금융, 의료 등 정확성이 중요한 도메인
  • 저장 공간 제약: 저장 공간이 제한적인 환경
  • 단순한 쿼리: JOIN이 단순하고 성능 문제가 없는 경우

반정규화 구현 전략

1. 단계적 적용

  1. 성능 측정: 현재 쿼리 성능 및 병목 지점 파악
  2. 작은 범위 테스트: 특정 테이블/컬럼부터 반정규화 적용
  3. 성능 비교: 반정규화 전후 성능 비교 및 모니터링
  4. 점진적 확장: 효과가 검증되면 다른 영역으로 확장

2. 데이터 동기화 전략

  • 트리거 기반: 데이터베이스 레벨에서 자동 동기화
  • 애플리케이션 로직: 서비스 레이어에서 동기화 처리
  • 이벤트 기반: 메시지 큐를 통한 비동기 동기화
  • 배치 작업: 주기적으로 데이터 일관성 검증 및 수정

3. 모니터링 및 유지보수

  • 성능 모니터링: 쿼리 성능 지속적 모니터링
  • 데이터 일관성 검증: 주기적인 데이터 무결성 검사
  • 문서화: 반정규화 적용 이유 및 동기화 로직 문서화

예시: 주문 시스템 반정규화

정규화된 구조

-- Orders 테이블
CREATE TABLE Orders (
    order_id INT PRIMARY KEY,
    customer_id INT,
    order_date DATETIME,
    FOREIGN KEY (customer_id) REFERENCES Customers(customer_id)
);

-- Customers 테이블
CREATE TABLE Customers (
    customer_id INT PRIMARY KEY,
    customer_name VARCHAR(100),
    customer_email VARCHAR(100)
);

-- OrderItems 테이블
CREATE TABLE OrderItems (
    order_item_id INT PRIMARY KEY,
    order_id INT,
    product_id INT,
    quantity INT,
    unit_price DECIMAL(10,2),
    FOREIGN KEY (order_id) REFERENCES Orders(order_id)
);

반정규화 적용

-- Orders 테이블에 고객 정보 및 총액 추가
CREATE TABLE Orders (
    order_id INT PRIMARY KEY,
    customer_id INT,
    customer_name VARCHAR(100),  -- 반정규화: 고객명 중복 저장
    customer_email VARCHAR(100),  -- 반정규화: 고객 이메일 중복 저장
    total_amount DECIMAL(10,2),   -- 반정규화: 총액 미리 계산
    order_date DATETIME,
    FOREIGN KEY (customer_id) REFERENCES Customers(customer_id)
);

-- 집계 테이블 생성
CREATE TABLE ProductStats (
    product_id INT PRIMARY KEY,
    total_sales INT,              -- 총 판매량
    total_revenue DECIMAL(10,2),  -- 총 매출
    average_rating DECIMAL(3,2),  -- 평균 평점
    last_updated DATETIME
);

동기화 로직 예시

-- 트리거: OrderItems 변경 시 Orders.total_amount 업데이트
CREATE TRIGGER update_order_total
AFTER INSERT OR UPDATE OR DELETE ON OrderItems
FOR EACH ROW
BEGIN
    UPDATE Orders
    SET total_amount = (
        SELECT SUM(quantity * unit_price)
        FROM OrderItems
        WHERE order_id = NEW.order_id
    )
    WHERE order_id = NEW.order_id;
END;

결론

반정규화는 성능과 일관성 사이의 트레이드오프를 다루는 기법입니다.

  • 적절히 사용하면: 조회 성능을 크게 향상시킬 수 있음
  • 남용하면: 데이터 일관성 문제와 유지보수 비용 증가

핵심 원칙:
1. 성능 문제가 명확히 확인된 경우에만 적용
2. 데이터 동기화 전략을 반드시 수립
3. 지속적인 모니터링과 검증 필요
4. 문서화를 통한 팀 내 공유


참고

  • 데이터베이스 정규화 (Normalization)
  • 데이터베이스 인덱싱 전략
  • 읽기/쓰기 분리 (Read/Write Splitting)
  • 캐싱 전략 (Caching Strategy)
profile
백엔드 새싹

0개의 댓글