BioPlayground

🧬
목록으로

관계형 데이터베이스 — JOIN과 정규화

왜 테이블을 나누는지, JOIN으로 어떻게 합치는지, 정규화가 왜 필요한지 실제 예제로 이해합니다.

중급
|
8
|
검증 완료 (2026-07)
진행률0/18 (0%)

관계형 데이터베이스 — 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_idusers.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 JOINLEFT JOIN을 가장 많이 씁니다.


정규화 — 왜 나누는가

정규화의 핵심 원칙은 단순합니다: 하나의 사실은 한 곳에만 저장한다.

정규화 전정규화 후효과
고객명이 주문마다 반복users 테이블에 1번만중복 제거
이메일 변경 시 N행 수정1행만 수정일관성 보장
주문 삭제 시 고객 소실고객 독립 존재데이터 보존

정규화가 "항상 좋은 것"은 아닙니다 — 테이블이 너무 많이 쪼개지면 JOIN이 복잡해지고 성능이 떨어질 수 있습니다. 실무에서는 성능을 위해 의도적으로 중복을 허용하기도 합니다(비정규화). 하지만 기본은 정규화입니다.