반정규화는 정규화된 데이터베이스 구조에서 성능 향상이나 특정 목적을 위해 의도적으로 정규화 규칙을 완화하는 데이터베이스 설계 기법입니다.
| 구분 | 정규화 | 반정규화 |
|---|---|---|
| 목적 | 데이터 중복 제거, 무결성 보장 | 성능 향상, 조회 속도 개선 |
| 데이터 중복 | 최소화 | 의도적 중복 허용 |
| 저장 공간 | 효율적 | 상대적으로 비효율적 |
| 데이터 일관성 | 높음 | 낮음 (관리 필요) |
| 업데이트 비용 | 낮음 | 높음 (여러 곳 수정 필요) |
| 조회 성능 | 상대적으로 느림 (JOIN 필요) | 빠름 (단일 테이블 조회) |
설명: 다른 테이블의 데이터를 현재 테이블에 중복 저장
예시:
-- 정규화된 구조
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 테이블도 업데이트 필요
설명: 자주 함께 조회되는 테이블을 하나로 합침
예시:
-- 정규화된 구조
Users 테이블: user_id, username, email
UserProfiles 테이블: user_id, address, phone, birth_date
-- 반정규화: 두 테이블 병합
Users 테이블: user_id, username, email, address, phone, birth_date
장점: 사용자 정보 조회 시 JOIN 불필요
단점: NULL 값 증가 가능, 테이블 크기 증가
설명: 계산된 값을 미리 저장하여 조회 시 계산 비용 절감
예시:
-- 정규화된 구조
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도 업데이트 필요
설명: 동일한 데이터를 다른 구조로 저장하여 다양한 조회 패턴 지원
예시:
-- 원본 테이블 (정규화)
Transactions: transaction_id, user_id, amount, created_at
-- 반정규화: 보고서용 테이블
DailyReports: date, user_id, total_amount, transaction_count
장점: 보고서 생성 속도 향상
단점: 데이터 동기화 로직 필요, 저장 공간 증가
설명: 자주 조회되는 집계 데이터를 미리 계산하여 저장
예시:
-- 반정규화: 집계 테이블
ProductStats:
product_id,
total_sales,
average_rating,
review_count,
last_updated
장점: 복잡한 집계 쿼리 대신 단순 SELECT로 조회
단점: 원본 데이터 변경 시 집계 테이블 갱신 필요
-- 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. 문서화를 통한 팀 내 공유