관계형 데이터베이스 — JOIN과 정규화
이 토픽을 마치면
테이블을 왜 나누는지 설명할 수 있고, JOIN으로 데이터를 합치는 SQL을 작성할 수 있습니다.
하나의 테이블로는 부족하다
온라인 쇼핑몰을 만든다고 합시다. 주문 정보를 하나의 테이블에 전부 넣으면 어떻게 될까요?
text
orders (모든 정보를 한 테이블에):
+----+--------+-------+----------+--------+
| id | 고객명 | 이메일 | 상품명 | 가격 |
+----+--------+-------+----------+--------+
| 1 | 김훈 | h@ex | 노트북 | 150만 |
| 2 | 김훈 | h@ex | 마우스 | 5만 |
| 3 | 이수 | s@ex | 키보드 | 10만 |
+----+--------+-------+----------+--------+문제가 보이시나요?
- 중복: "김훈"과 "h@ex"가 주문할 때마다 반복됩니다
- 수정 위험: 김훈이 이메일을 바꾸면 모든 행을 고쳐야 합니다. 하나라도 빠뜨리면 불일치
- 삭제 위험: 김훈의 주문을 전부 삭제하면 고객 정보 자체가 사라집니다
테이블 분리 — 정규화의 기본
해결책은 관련 있는 데이터를 별도 테이블로 분리하는 것입니다.
text
users 테이블: orders 테이블:
+----+--------+-------+ +----+---------+----------+--------+
| id | name | email | | id | user_id | product | price |
+----+--------+-------+ +----+---------+----------+--------+
| 1 | 김훈 | h@ex | | 1 | 1 | 노트북 | 150만 |
| 2 | 이수 | s@ex | | 2 | 1 | 마우스 | 5만 |
+----+--------+-------+ | 3 | 2 | 키보드 | 10만 |
+----+---------+----------+--------+orders.user_id가 users.id를 가리킵니다. 이것이 외래키(Foreign Key) — 두 테이블을 연결하는 고리입니다.
이렇게 중복을 제거하고 테이블을 분리하는 과정을 **정규화(Normalization)**라고 합니다.
JOIN — 분리된 테이블을 합치기
테이블을 나눴으니, 다시 합쳐서 볼 방법이 필요합니다. 그것이 JOIN입니다.
sql
-- 주문 목록에 고객 이름을 붙여서 조회
SELECT users.name, orders.product, orders.price
FROM orders
JOIN users ON orders.user_id = users.id;결과:
text
+--------+----------+--------+
| name | product | price |
+--------+----------+--------+
| 김훈 | 노트북 | 150만 |
| 김훈 | 마우스 | 5만 |
| 이수 | 키보드 | 10만 |
+--------+----------+--------+JOIN ... ON 뒤에 어떤 열을 기준으로 매칭할지 지정합니다. orders.user_id = users.id — 주문의 user_id가 사용자의 id와 같은 행끼리 합칩니다.
JOIN의 종류
sql
-- INNER JOIN: 양쪽 모두 매칭되는 행만 (기본값)
SELECT * FROM orders JOIN users ON orders.user_id = users.id;
-- LEFT JOIN: 왼쪽 테이블은 전부, 오른쪽은 매칭되는 것만
-- 주문이 없는 고객도 포함
SELECT users.name, orders.product
FROM users
LEFT JOIN orders ON users.id = orders.user_id;
-- 결과: 주문 없는 고객은 product가 NULL로 표시| JOIN 유형 | 설명 |
|---|---|
INNER JOIN | 양쪽 다 있는 것만 |
LEFT JOIN | 왼쪽 전부 + 오른쪽은 있으면 붙임 |
RIGHT JOIN | 오른쪽 전부 + 왼쪽은 있으면 붙임 |
실무에서는 INNER JOIN과 LEFT JOIN을 가장 많이 씁니다.
정규화 — 왜 나누는가
정규화의 핵심 원칙은 단순합니다: 하나의 사실은 한 곳에만 저장한다.
| 정규화 전 | 정규화 후 | 효과 |
|---|---|---|
| 고객명이 주문마다 반복 | users 테이블에 1번만 | 중복 제거 |
| 이메일 변경 시 N행 수정 | 1행만 수정 | 일관성 보장 |
| 주문 삭제 시 고객 소실 | 고객 독립 존재 | 데이터 보존 |
정규화가 "항상 좋은 것"은 아닙니다 — 테이블이 너무 많이 쪼개지면 JOIN이 복잡해지고 성능이 떨어질 수 있습니다. 실무에서는 성능을 위해 의도적으로 중복을 허용하기도 합니다(비정규화). 하지만 기본은 정규화입니다.