본문 바로가기
컴퓨터과학

데이터 정규화와 역정규화! 데이터베이스 최적화의 핵심 개념 완벽 정리

by 코드그래피 2025. 2. 3.
반응형

데이터베이스를 설계할 때 가장 중요한 목표는 데이터 무결성(Data Integrity)과 성능 최적화입니다.

이를 달성하기 위한 대표적인 기법이 바로 데이터 정규화(Normalization)와 역정규화(Denormalization) 입니다.

정규화데이터 중복을 제거하여 데이터 일관성을 유지하는 방법,

역정규화성능 최적화를 위해 일부 중복을 허용하는 방법입니다.

이번 글에서는 정규화와 역정규화의 개념, 장단점, 적용 사례, 그리고 SQL 예제를 포함하여

데이터베이스 설계에서 반드시 알아야 할 핵심 개념을 상세히 설명하겠습니다.


1. 데이터 정규화(Normalization)란?

📌 정규화란?

데이터 정규화(Normalization)중복을 최소화하고 데이터 무결성을 유지하기 위한 데이터베이스 설계 기법입니다.

즉, 데이터를 구조적으로 정리하여 일관성을 유지하고, 삽입/수정/삭제 이상(Anomaly)을 방지하는 것이 목적입니다.

정규화는 이상(Anomaly) 을 방지하기 위해 수행됩니다.

삽입 이상(Insertion Anomaly) : 불필요한 데이터 입력이 필요함

수정 이상(Update Anomaly) : 한 곳에서 변경하면 다른 곳도 수정해야 함

삭제 이상(Deletion Anomaly) : 불필요한 데이터가 삭제되면서 중요한 데이터까지 함께 삭제됨


2. 정규화의 단계 (1NF ~ 5NF)

정규화는 여러 단계로 이루어지며, 단계가 올라갈수록 데이터 중복이 줄어들고 무결성이 향상됩니다.

✅ 제1정규형 (1NF, First Normal Form)

각 컬럼이 원자값(Atomic Value, 더 이상 쪼갤 수 없는 값)을 가져야 함

중복된 행이 없어야 함

🔹 예제 (정규화 전)
ID 이름 전화번호
1 홍길동 010-1234-5678, 02-567-1234
2 이순신 010-2345-6789
🔹 제1정규형 적용 후
ID 이름 전화번호
1 홍길동 010-1234-5678
1 홍길동 02-567-1234
2 이순신 010-2345-6789
제1정규형 SQL 예제
CREATE TABLE customers (
    customer_id INT PRIMARY KEY,
    name VARCHAR(100) NOT NULL
);

CREATE TABLE phone_numbers (
    customer_id INT,
    phone_number VARCHAR(20),
    PRIMARY KEY (customer_id, phone_number),
    FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);

✅ 제2정규형 (2NF, Second Normal Form)

1NF를 만족하면서, 부분 함수 종속(Partial Dependency)이 제거되어야 함

즉, 기본 키의 일부만을 참조하는 컬럼이 없어야 함

🔹 예제 (정규화 전)
주문ID 고객ID 고객명 제품ID 제품명
1 100 홍길동 P001 키보드
2 200 이순신 P002 마우스
🔹 제2정규형 적용 후 (고객 테이블과 제품 테이블로 분리)
고객 테이블
고객ID 고객명
100 홍길동
200 이순신
제품 테이블
제품ID 제품명
P001 키보드
P002 마우스
주문 테이블
주문ID 고객ID 제품ID
1 100 P001
2 200 P002
제2정규형 SQL 예제
CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    customer_id INT,
    FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);

CREATE TABLE products (
    product_id INT PRIMARY KEY,
    product_name VARCHAR(100) NOT NULL
);

CREATE TABLE order_details (
    order_id INT,
    product_id INT,
    quantity INT NOT NULL,
    PRIMARY KEY (order_id, product_id),
    FOREIGN KEY (order_id) REFERENCES orders(order_id),
    FOREIGN KEY (product_id) REFERENCES products(product_id)
);

✅ 제3정규형 (3NF, Third Normal Form)

2NF를 만족하면서, 이행적 종속(Transitive Dependency)이 제거되어야 함

즉, 기본 키에 종속되지 않는 속성은 별도의 테이블로 분리해야 함

🔹 예제 (정규화 전)
직원ID 직원명 부서ID 부서명
1 김철수 D01 인사팀
2 박영희 D02 개발팀
🔹 제3정규형 적용 후
부서 테이블 분리
부서ID 부서명
D01 인사팀
D02 개발팀
직원 테이블
직원ID 직원명 부서ID
1 김철수 D01
2 박영희 D02
📌 시나리오:

• 고객이 주문을 할 수 있으며, 각 주문에는 여러 개의 제품이 포함될 수 있다.

• 주문 정보는 orders 테이블, 고객 정보는 customers 테이블, 제품 정보는 products 테이블에 저장된다.

📌 정규화된 테이블 설계
-- 고객 테이블 (1NF, 2NF, 3NF 적용)
CREATE TABLE customers (
    customer_id INT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL
);

-- 제품 테이블
CREATE TABLE products (
    product_id INT PRIMARY KEY,
    product_name VARCHAR(100) NOT NULL,
    price DECIMAL(10,2) NOT NULL
);

-- 주문 테이블
CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    customer_id INT,
    order_date DATE NOT NULL,
    FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);

-- 주문 상세 테이블 (N:M 관계 해결)
CREATE TABLE order_details (
    order_id INT,
    product_id INT,
    quantity INT NOT NULL,
    PRIMARY KEY (order_id, product_id),
    FOREIGN KEY (order_id) REFERENCES orders(order_id),
    FOREIGN KEY (product_id) REFERENCES products(product_id)
);
📌 정규화된 데이터 삽입
-- 고객 추가
INSERT INTO customers (customer_id, name, email) VALUES (1, '홍길동', 'hong@example.com');
INSERT INTO customers (customer_id, name, email) VALUES (2, '이순신', 'lee@example.com');

-- 제품 추가
INSERT INTO products (product_id, product_name, price) VALUES (101, '키보드', 25000);
INSERT INTO products (product_id, product_name, price) VALUES (102, '마우스', 15000);

-- 주문 추가
INSERT INTO orders (order_id, customer_id, order_date) VALUES (1001, 1, '2024-02-01');
INSERT INTO orders (order_id, customer_id, order_date) VALUES (1002, 2, '2024-02-02');

-- 주문 상세 추가
INSERT INTO order_details (order_id, product_id, quantity) VALUES (1001, 101, 1);
INSERT INTO order_details (order_id, product_id, quantity) VALUES (1001, 102, 2);
INSERT INTO order_details (order_id, product_id, quantity) VALUES (1002, 101, 1);
📌 정규화된 데이터 조회 (JOIN 사용)
SELECT o.order_id, c.name AS customer_name, p.product_name, od.quantity, p.price
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
JOIN order_details od ON o.order_id = od.order_id
JOIN products p ON od.product_id = p.product_id
WHERE o.order_id = 1001;
📌 결과 예시 (정규화된 구조에서의 조회 결과)
order_id customer_name order_date product_name quantity price
1001 홍길동 2024-02-01 키보드 1 25000
1001 홍길동 2024-02-01 마우스 2 15000
✅ 정규화의 장점:

✔ 중복 데이터 최소화

✔ 데이터 무결성 유지

✔ 수정/삭제 시 한 곳만 변경하면 됨

⚠️ 단점:

• 여러 테이블을 조인해야 하므로 읽기 성능이 느려질 수 있음


3. 역정규화(Denormalization)란?

📌 역정규화란?

역정규화(Denormalization)성능을 향상시키기 위해 정규화된 데이터를 일부 다시 합치는 과정입니다.

즉, 데이터 중복을 허용하는 대신, JOIN 연산을 줄여 조회 속도를 높이는 방법입니다.

✅ 역정규화가 필요한 경우

1. JOIN 연산이 많아 성능이 저하될 경우

2. 데이터 조회가 빈번한 경우

3. 읽기(Read) 성능을 높여야 하는 경우

4. 실시간 분석이 필요한 경우 (로그 데이터 등)

📌 역정규화 SQL 예제 (성능 최적화)

📌 시나리오:

• 주문 상세 테이블과 제품 정보를 하나의 테이블에 병합하여 조회 속도를 높임.

• 고객명, 주문 날짜, 제품명, 수량, 가격을 한 번에 조회 가능하도록 설계.

📌 역정규화된 테이블 설계
CREATE TABLE order_summary (
    order_id INT PRIMARY KEY,
    customer_name VARCHAR(100),
    order_date DATE NOT NULL,
    product_name VARCHAR(100),
    quantity INT NOT NULL,
    price DECIMAL(10,2) NOT NULL
);
📌 역정규화된 데이터 삽입
INSERT INTO order_summary (order_id, customer_name, order_date, product_name, quantity, price)
VALUES 
    (1001, '홍길동', '2024-02-01', '키보드', 1, 25000),
    (1001, '홍길동', '2024-02-01', '마우스', 2, 15000),
    (1002, '이순신', '2024-02-02', '키보드', 1, 25000);
📌 역정규화된 데이터 조회 (JOIN 없이 단순 조회)
SELECT * FROM order_summary WHERE order_id = 1001;
📌 결과 예시 (역정규화된 구조에서의 조회 결과)
order_id customer_name order_date product_name quantity price
1001 홍길동 2024-02-01 키보드 1 25000
1001 홍길동 2024-02-01 마우스 2 15000
✅ 역정규화의 장점:

JOIN 연산 없이 빠르게 조회 가능

✔ 대량의 데이터 조회 시 성능 향상

⚠️ 단점:

데이터 중복 증가 (예: 홍길동 이름이 여러 번 저장됨)

수정 시 여러 레코드를 변경해야 함 (예: 고객명이 바뀌면 모든 주문을 수정해야 함)


4. 정규화 vs 역정규화 비교 (SQL 관점에서)

구분 정규화된 데이터베이스 역정규화된 데이터베이스
데이터 무결성 ✅ 무결성 유지 (중복 최소화) ❌ 중복 데이터 존재
조회 성능 JOIN 사용으로 속도 저하 가능 JOIN 없이 빠른 조회
데이터 수정 ✅ 수정 용이 (하나의 테이블만 변경) ❌ 중복 데이터로 인해 여러 레코드 수정 필요
적용 대상 트랜잭션 시스템 (OLTP) 데이터 분석 시스템 (OLAP)

5. 정규화와 역정규화를 고려한 설계 전략

OLTP(온라인 트랜잭션 시스템)정규화 적용

OLAP(데이터 분석 시스템, DW)역정규화 적용

SQL 예제

✅ 정규화된 테이블
CREATE TABLE customers (
    customer_id INT PRIMARY KEY,
    name VARCHAR(100)
);

CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    customer_id INT,
    product VARCHAR(100),
    FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
✅ 역정규화된 테이블 (JOIN 없이 조회 가능)
CREATE TABLE order_summary (
    order_id INT PRIMARY KEY,
    customer_name VARCHAR(100),
    product VARCHAR(100)
);

6. 결론: 언제 정규화와 역정규화를 선택해야 할까?

✔ 정규화(Normalization)

• 데이터 무결성 유지

• 중복 최소화

OLTP 시스템 (트랜잭션 처리용 DB) 에 적합

✔ 역정규화(Denormalization)

• 빠른 조회 속도

• JOIN 최소화

OLAP 시스템 (데이터 분석, BI 시스템) 에 적합

🚀 여러분의 시스템은 정규화를 사용할까요, 역정규화를 사용할까요?

댓글로 여러분의 의견을 공유해 주세요! 😊

반응형