정규화는 어떤 문제는 해결해주지만, 어떤 경우엔 오히려 다른 문제를 만들어. 특히 성능 쪽에서 말이지. 오늘은 너한테 어둠(가끔은 빛)의 기술, 바로 비정규화의 문을 열어줄게. 맞아, 정규화의 규칙을 깨도 돼... 하지만 똑똑하게 해야 해!
비정규화는 정규화랑 반대되는 과정이야. 정규화가 테이블을 논리적으로 쪼개서 중복을 최소화한다면, 비정규화는 데이터를 다시 합쳐서 성능을 높여주는 거지. 비정규화는 주로 부하가 크고 복잡한 쿼리를 자주 돌릴 때, 여러 테이블을 조인하다가 시스템이 느려질 때 많이 써.
비정규화는 데이터의 순수함과 쿼리 속도 사이의 타협이라고 할 수 있어.
언제 비정규화를 써야 할까?
모든 도구가 그렇듯, 비정규화도 언제 써야 하는지 아는 게 중요해. 이런 상황에서 써:
자주 쓰는 쿼리가 느려질 때. 부하가 큰 시스템에서 똑같은 쿼리(예: 집계 리포트나 aggregate)만 계속 돌리면, 여러 테이블 조인 때문에 시간이 엄청 오래 걸릴 수 있어. 비정규화로 이런 조인 횟수를 줄일 수 있지.
분석 작업이나 통계. 분석 시스템(BI — Business Intelligence)에서는 대량 데이터 분석이 필요해. 이럴 때 비정규화로 "미리 준비된" 데이터 덕분에 처리 속도가 빨라져.
복잡한 쿼리. 쿼리 하나에 다섯 개, 열 개, 아니 그 이상 테이블을 조인해야 한다면, DB가 엄청 느려질 수 있어. 비정규화로 쿼리 구조를 단순하게 만들 수 있지.
조인 개수가 상식 이상일 때. 쿼리에
JOIN이 25개나 들어가면, 이제는 접근 방식을 다시 생각해볼 때야.
비정규화 예시
예시 1: 인터넷 쇼핑몰. 정규화된 인터넷 쇼핑몰 DB에는 이런 테이블이 있을 수 있어:
customers— 고객 정보.orders— 주문 정보.products— 상품 정보.order_items— 주문에 포함된 상품.
정보를 가져오는 쿼리는 대충 이렇게 생겼어:
SELECT
c.customer_name,
o.order_date,
p.product_name,
oi.quantity
FROM
customers c
JOIN
orders o ON c.customer_id = o.customer_id
JOIN
order_items oi ON o.order_id = oi.order_id
JOIN
products p ON oi.product_id = p.product_id
WHERE
c.customer_id = 42;
근데 만약 우리 쇼핑몰이 하루에 수십만 건의 주문을 처리한다면? 이 쿼리는 조인 개수가 많아서 너무 느려질 거야.
해결책: 비정규화.
자주 쓰는 정보를 위한 테이블을 만들어보자:
CREATE TABLE order_summary AS
SELECT
c.customer_id,
c.customer_name,
o.order_id,
o.order_date,
p.product_id,
p.product_name,
oi.quantity
FROM
customers c
JOIN
orders o ON c.customer_id = o.customer_id
JOIN
order_items oi ON o.order_id = oi.order_id
JOIN
products p ON oi.product_id = p.product_id;
이제 데이터가 필요하면 그냥 order_summary에서 쿼리하면 돼:
SELECT * FROM order_summary WHERE customer_id = 42;
예시 2: 분석 시스템. 이벤트 티켓 판매 회사의 DB를 다룬다고 해보자. 테이블은 이렇게 있어:
events— 이벤트 정보.sales— 티켓 판매 데이터.
분석가가 모든 이벤트별로 티켓 한 장당 평균 수익 리포트를 만들고 싶으면, 정규화 구조에서는 매번 집계 쿼리를 돌려야 해:
SELECT
e.event_name,
AVG(s.price) AS avg_ticket_price
FROM
events e
JOIN
sales s ON e.event_id = s.event_id
GROUP BY
e.event_name;
이 쿼리는, 특히 판매 데이터가 수백만 줄이면, 꽤 느릴 수 있어.
해결책: 비정규화. 집계 데이터를 따로 저장하는 테이블을 만들어보자:
CREATE TABLE event_summary AS
SELECT
e.event_id,
e.event_name,
COUNT(s.sale_id) AS ticket_count,
SUM(s.price) AS total_revenue,
AVG(s.price) AS avg_ticket_price
FROM
events e
JOIN
sales s ON e.event_id = s.event_id
GROUP BY
e.event_id, e.event_name;
이제 리포트는 집계 테이블에서 훨씬 빠르게 나와:
SELECT
event_name,
avg_ticket_price
FROM
event_summary;
비정규화의 결과
비정규화는 확실히 쿼리를 빠르게 해주지만, 모든 문제를 해결해주는 마법 지팡이는 아니야. 이걸 쓰면 이런 점을 겪을 수 있어.
첫째 — 데이터 중복. 똑같은 정보가 여러 군데 저장되면, DB 용량이 금방 커지고 관리도 힘들어져.
둘째 — 데이터 업데이트가 더 어려워져. 예를 들어, 고객 정보가 customers 테이블에도 있고, order_summary에도 복사돼 있다면, 고객이 이름이나 주소를 바꾸면 두 군데 다 업데이트해야 해. 한 군데만 바꾸면 데이터가 안 맞아서 에러가 생길 수 있어.
셋째 — 이런 중복 때문에 헷갈리기 쉽고 실수도 잘 나와. 같은 문서의 여러 버전이 있을 때 어떤 게 맞는지 헷갈리는 거랑 비슷해.
마지막으로, 이런 DB는 유지보수랑 확장도 더 어려워져. 데이터 복사본이 항상 동기화되도록 트리거나 스크립트를 따로 짜야 하거든. 개발자한테 일이 더 늘어나는 거지.
결론적으로, 비정규화는 장단점을 잘 알고 똑똑하게 써야 하는 도구야.
GO TO FULL VERSION