부모 / 자식 —
외래키를 어디에 둘까
섹션 3에서 외래키가 무엇인지는 이미 배웠습니다. 이번에는 만들어진 외래키를 찾는 데서 끝나지 않아요. 업무 규칙을 읽고 왜 외래키가 그쪽 테이블에 있어야 하는지를 직접 판단해 봅니다.
이번 섹션의 여정
완료 ✓
지금 여기
1:1 · 1:N · N:M
ERD · 정규화 · 실습
부모와 자식을 정하는 기준은 하나뿐입니다
부모는 다른 테이블이 참조하는 키를 가진 쪽입니다. 보통 기본키를 참조해요. 자식은 부모의 키를 자기 행에 외래키로 기록하는 쪽입니다.
관계형 데이터베이스에서는 중복되지 않는 다른 키를 참조할 수도 있습니다. 다만
우리 shop 의 외래키 네 개는 모두 부모의 기본키를 가리킵니다.
이름 때문에 생기는 오해부터 지우고 가겠습니다.
| 이런 뜻일까? | 아닙니다 |
|---|---|
| 부모가 더 중요하고 자식은 덜 중요하다 | × 중요도와 전혀 관계없다 |
| 부모가 오래된 데이터, 자식이 새 데이터다 | × 데이터의 나이와 무관하다 |
| 부모를 먼저 만드니까 부모다 | × 생성 순서는 기준이 아니라 결과다 |
업무 규칙에서 FK 위치가 나옵니다
“주문 한 건은 회원 한 명의 주문이다” 라는 규칙을 보겠습니다.
주문 한 건을 저장할 때 우리는 “이 주문은 어느 회원의 것인가” 를 기록해야 합니다. 그래서 주문 행이 회원의 번호를 갖습니다. 실제 구조는 orders.member_id가 members.member_id를 참조하죠 — members가 부모, orders가 자식입니다.
반대로 해보면 왜 그래야 하는지가 분명해집니다.
회원 행에 주문 번호를 넣는다면?
재주문할 때기존
order_id를 바꾸거나 덮어써야 한다order_id_1 · 2 · 3주문이 늘 때마다 컬럼을 늘려야 한다
결국회원 한 명의 정보에 주문 여러 건을 억지로 밀어 넣게 된다
주문이 추가되면주문 행을 하나 더 만들면 된다
각 행에같은 회원 번호를 기록하기만 하면 된다
구조는 그대로컬럼을 늘릴 일이 없다
외래키 위치는 관습으로 외우는 게 아닙니다 — 각 자식 행이 어느 부모에 속하는지 기록해야 한다는 업무 규칙에서 나옵니다.
관계를 읽는 두 개의 문장
새 관계를 설계할 때는 양쪽에서 문장을 만들어 보세요.
회원과 주문에 적용하면 이렇게 됩니다.
| 방향 | 질문 |
|---|---|
| 부모 → 자식 | 회원 한 명은 주문을 몇 건까지 할 수 있는가? |
| 자식 → 부모 | 주문 한 건은 회원을 반드시 가져야 하는가, 몇 명의 주문인가? |
최소와 최대 개수를 1:1, 1:N, N:M 같은 표기로 정리하는 방법은 다음 4-3
강의에서 자세히 다룹니다. 오늘은 이 문장으로 관계를 읽는 데 집중하세요.
shop 의 네 관계를 차례로 읽습니다
| 항목 | 내용 |
|---|---|
| 부모 / 자식 | members(부모) / orders(자식) |
| 외래키 | orders.member_id → members.member_id |
| 부모 쪽 | 회원 한 명은 주문이 없을 수도, 여러 건일 수도 있다 |
| 자식 쪽 | 주문 한 건은 회원 한 명을 반드시 가리킨다 |
orders.member_id가 NOT NULL이고 외래키이기 때문에, 비어 있거나 존재하지 않는 회원 번호를 가질 수 없습니다.
| 항목 | 내용 |
|---|---|
| 부모 / 자식 | categories(부모) / products(자식) |
| 외래키 | products.category_id → categories.category_id |
| 부모 쪽 | 카테고리 하나에는 상품이 없을 수도, 여러 개일 수도 있다 |
| 자식 쪽 | 상품 한 개는 카테고리 한 개를 반드시 가리킨다 |
| 항목 | 내용 |
|---|---|
| 부모 / 자식 | orders(부모) / order_items(자식) |
| 외래키 | order_items.order_id → orders.order_id |
| 부모 쪽 | 주문 한 건에는 주문상세가 여러 개 들어갈 수 있다 |
| 자식 쪽 | 주문상세 한 행은 반드시 주문 한 건에 속한다 |
현재 외래키만으로는 주문상세가 하나도 없는 주문을 막지 못합니다. 업무에서 “완료된 주문에는 상품이 최소 한 개 있어야 한다” 는 규칙이 필요하다면, 외래키 외의 처리도 함께 설계해야 해요.
| 항목 | 내용 |
|---|---|
| 부모 / 자식 | products(부모) / order_items(자식) |
| 외래키 | order_items.product_id → products.product_id |
| 부모 쪽 | 상품 한 개는 아직 한 번도 주문되지 않을 수도, 여러 주문상세에 쓰일 수도 있다 |
| 자식 쪽 | 주문상세 한 행은 상품 한 개를 반드시 가리킨다 |
한 행 안의 order_id로 orders를 가리키고, product_id로 products를 가리킵니다.
부모·자식은 관계마다 달라지는 역할입니다
전체 구조에서 orders를 다시 보겠습니다.
| 어느 관계에서 | orders 의 역할 | 이유 |
|---|---|---|
| members 와의 관계 | 자식 | 회원의 키를 member_id 라는 FK 로 가지고 있다 |
| order_items 와의 관계 | 부모 | 자신의 order_id 가 주문상세에서 참조된다 |
“orders 는 부모 테이블이다” 처럼 단독으로 외우면 안 됩니다. 항상 “어느 테이블과의 관계에서” 부모인지 자식인지 말해야 합니다.
부모와 자식은 테이블에 영구히 붙는 신분이 아니라 — 관계 하나에서 맡는 역할입니다.
부모·자식을 찾은 뒤 남는 두 질문
현재 shop DB의 외래키 네 개는 모두 NOT NULL이라서 자식 행마다 부모가 반드시 필요합니다. 하지만 모든 서비스가 이렇게 설계되는 것은 아닙니다. 연결을 선택 사항으로 둘지, 부모 삭제를 막을지, 다른 방식으로 처리할지는 업무 규칙에 따라 결정해야 해요.
지금은 정답을 외우지 말고 — 반드시 물어봐야 할 설계 질문으로 기억해 두세요.
마스터·트랜잭션은 다른 분류축입니다
실무에서는 부모·자식과 함께 마스터 테이블, 트랜잭션 테이블이라는 말도 자주 듣습니다. 이 둘은 서로 다른 기준이에요.
| 분류축 | 판단 질문 | shop 예시 |
|---|---|---|
| 부모 / 자식 | 누가 참조되고 누가 FK 를 가지는가? (관계에서의 역할) | orders 는 members 의 자식이자 order_items 의 부모 |
| 마스터 / 트랜잭션 | 어떤 성격의 업무 데이터를 담는가? (비즈니스 분류) | members · categories · products = 마스터 / orders · order_items = 트랜잭션 |
회원, 카테고리, 상품처럼 업무의 기준이 되는 정보를 관리하는 테이블은 마스터 성격, 주문처럼 발생한 사건과 그 상세를 기록하는 테이블은 트랜잭션 성격으로 볼 수 있습니다.
products 는 마스터 성격이지만 category_id 외래키를 가진 자식입니다.
orders 는 트랜잭션 성격이면서 members 의 자식이자 order_items 의
부모예요. 두 축은 서로 독립입니다.
한눈에 정리
| 관계 | 부모 | 자식 | 외래키 |
|---|---|---|---|
| 회원 — 주문 | members | orders | orders.member_id → members.member_id |
| 카테고리 — 상품 | categories | products | products.category_id → categories.category_id |
| 주문 — 주문상세 | orders | order_items | order_items.order_id → orders.order_id |
| 상품 — 주문상세 | products | order_items | order_items.product_id → products.product_id |
부모는 참조되는 키를 가진 쪽이고, 자식은 그 키를 외래키로 기록하는 쪽입니다. 그 역할은 중요도나 생성 순서가 아니라 관계마다 정해집니다.
이제 연결의 방향은 알았습니다. 그런데 한 회원은 주문을 몇 건까지 할 수 있을까요? 주문 한 건은 회원 몇 명의 것일까요? 다음 강의에서 그 개수를 표기로 정리합니다.