바이브 코딩 시대의 데이터베이스4-6 실무 ERD 분석
테크타니 LEARN — 섹션 04 · DB 모델링

실무 ERD 분석 —
지금 한 행은 무엇인가

ERD에서 길을 찾았다고 답이 바로 나오지는 않습니다. 관계를 하나 지날 때마다 한 행의 뜻이 바뀌고, 같은 대상이 여러 번 나타나기도 해요. 오늘은 실습 DB의 실제 데이터를 따라가며 행의 단위를 확인하는 습관을 만듭니다.

난이도보통소요8분준비물4-5 완료오늘10행 ≠ 11개

이번 섹션의 여정

4-4 ERD 읽는 법

완료 ✓

4-5 정규화

완료 ✓

4-6 실무 ERD 분석

지금 여기

4-7 모델링 종합 실습

요구사항 → ERD

길을 찾았다고 답이 나오지는 않습니다

앞 강의까지 우리는 ERD에서 필요한 길을 찾는 법과, 각 사실을 알맞은 테이블로 나누는 이유를 배웠습니다.

그런데 길을 찾은 다음이 진짜 시작이에요. 관계를 하나 지날 때마다 행이 늘어날 수 있고, 같은 대상이 여러 번 나타날 수도 있으니까요.

⭐ 오늘 계속 물을 두 질문지금 한 행은 무엇인가? 그리고 내가 원하는 답도 그 단위인가?

이 두 질문만 놓치지 않으면 됩니다. 그럼 실제 데이터로 확인해 볼게요.

회원 한 명 → 주문 6건 → 주문상세 10행

우리 shop김철수 회원(member_id 1번) 에서 출발합니다.

경로 추적 — 김철수에서 주문상세까지
members member_id = 1 · 김철수
↓ orders.member_id 를 따라간다
orders 1 · 6 · 14 · 20 · 27 · 34 → 6행
↓ order_items.order_id 를 따라간다
order_items 주문 6건에 달린 상세 줄 → 10행

회원 1행에서 출발했는데 주문으로 넘어가자 6행이 되고, 주문상세로 한 번 더 내려가자 10행이 됐습니다. 실제로 어떤 줄들인지 펼쳐 보겠습니다.

shop DB — 김철수의 주문상세 10행
order_idproduct_idproduct_namequantity
11라운드 티셔츠1
116프리미엄 그래놀라2
69무선 이어폰1
1422SQL 입문서1
1423데이터 모델링 실전1
1424AI 시대 개발자1
208패딩 점퍼1
279무선 이어폰1
2713무선 마우스1
3423데이터 모델링 실전1
10행 — 그런데 quantity 를 모두 더하면 11개입니다
주문 1번은 2줄, 14번은 3줄, 27번은 2줄 · 나머지 세 주문은 각각 1줄

주문 하나가 상세 여러 줄로 펼쳐지기 때문에 주문 6건이 상세 10행이 됐어요.

10행과 11개는 서로 다른 질문의 답입니다

방금 표에서 quantity를 모두 더하면 11개입니다. 행은 분명 10줄인데 왜 숫자가 다를까요?

주문상세 한 행은 주문에 들어간 상품 한 종류를 뜻하고, 그 행 안의 수량은 1보다 클 수 있기 때문입니다. 김철수의 주문 1번에 담긴 프리미엄 그래놀라가 2개였죠.

같은 데이터, 다른 질문
질문보는 것
주문상세가 몇 줄인가?행의 개수10행
상품 수량을 모두 더하면 몇 개인가?행 안의 quantity 합11개
행을 세는 것과 행 안의 숫자를 더하는 것은 다른 질문입니다

이 둘을 섞으면 이런 일이 생깁니다

행 수와 수량 합계를 같은 단위로 다루면
  • 보고서에“김철수가 상품 10개를 샀다”고 잘못 적는다

  • 재고 계산에서실제로 나간 개수보다 1개 적게 잡힌다

  • 더 나쁜 건숫자가 비슷해서 틀린 줄 모르고 넘어간다

질문의 단위를 먼저 정하면 ✓
  • “몇 줄인가”주문상세 행을 센다 — 10행

  • “몇 개인가”행 안의 quantity 를 더한다 — 11개

  • 결과어떤 숫자를 말하는지 스스로도, 듣는 사람도 안다

행 수수량 합계는 애초에 단위가 다릅니다. 같은 표에서 나왔다고 같은 종류의 숫자가 아니에요.

반대 방향 — 상품 하나에서 회원 네 명으로

이번에는 출발점을 바꿔서 상품 23번, 데이터 모델링 실전에서 시작해 보겠습니다.

shop DB — 상품 23번이 담긴 주문상세
order_idproduct_idquantity그 주문의 member_id회원
52315최지훈
142311김철수
282319조성민
332312이영희
342311김철수
402319조성민
주문상세는 6행 — 그런데 member_id 를 보면 1번과 9번이 두 번씩 나타납니다

회원번호를 순서대로 늘어놓으면 5 · 1 · 9 · 2 · 1 · 9입니다. 여기서 중복을 빼면 남는 번호는 1 · 2 · 5 · 9네 명이에요.

같은 경로, 다른 질문
질문보는 것
이 상품이 몇 개 주문에 들어갔는가?주문상세 행을 그대로 센다6행
이 상품이 들어 있는 주문의 서로 다른 회원은 몇 명인가?중복 회원번호를 한 번씩만 센다4명
같은 길을 걸어도 — 무엇을 세려는지에 따라 답이 달라집니다
이 4명을 '구매 확정 고객'이라고 부르면 안 됩니다

현재 orders 에는 취소·결제 상태 컬럼이 없습니다. 그래서 이 네 명은 “상품 23번이 들어 있는 주문의 회원” 일 뿐이에요. 데이터에 없는 의미를 이름에 얹지 않는 것도 분석의 일부입니다.

경로를 지날 때마다 “한 행”을 다시 묻습니다

이제 두 경로를 나란히 놓고, 관계를 하나 지날 때마다 한 행의 뜻이 어떻게 바뀌는지 정리해 볼게요.

경로 A — 김철수(member_id 1) 에서 내려가기
지금 있는 곳한 행의 뜻김철수 기준
members회원 한 명1행
orders주문 한 건6행
order_items한 주문에 담긴 상품 한 종류10행
order_items 의 quantity 합행이 아니라 낱개 수량11개
아래로 한 칸 내려갈 때마다 한 행이 가리키는 대상이 더 작아집니다
경로 B — 상품 23번에서 거슬러 올라가기
지금 있는 곳한 행의 뜻상품 23번 기준
products상품 한 개1행
order_items그 상품이 담긴 상세 한 줄6행
orders그 상세가 속한 주문 한 건6행
members (중복 그대로)주문마다 딸려온 회원6행
members (중복 제거)서로 다른 회원4명
위로 거슬러 올라갈 때는 같은 대상이 여러 번 나타납니다
⭐ 관계를 하나 지날 때마다

“지금 한 행은 회원인가, 주문인가, 주문상세인가?” 이 질문을 건너뛰면 숫자는 나오지만 그 숫자가 무엇인지 모르게 됩니다.

그리고 마지막에는 하나 더 정해야 해요. 중복을 그대로 셀지, 서로 다른 대상만 셀지.

다음 섹션의 예고편입니다

섹션 5에서 여러 테이블을 한 번에 조회하면 결과 행이 예상보다 많아지는 순간이 옵니다. 그때 당황하지 않는 이유가 바로 오늘 만든 이 감각이에요. 문법은 그때 배우고, 지금은 값을 따라가는 눈만 챙겨 갑니다.

관계선이 보여주지 않는 규칙 ① — 중복

ERD의 선은 누가 누구와 연결되는지를 보여줍니다. 하지만 업무 규칙 중에는 선만으로 표현되지 않는 것들이 있어요.

여기부터는 가상 예시입니다 · shop DB 에 없습니다

아래 나오는 users, posts, post_likes, follows, rooms, reservations 는 설명을 위해 지어낸 가상 테이블입니다. 우리 실습 DB 에는 존재하지 않아요.

SNS의 좋아요를 생각해 봅시다. 사용자와 게시글 사이에 좋아요 테이블을 두면 누가 어떤 글을 좋아했는지는 깔끔하게 연결됩니다.

가상 예시 — post_likes 로 연결한 좋아요
user_idpost_id외래키가 보장하는 것
7101존재하는 사용자 · 존재하는 게시글만 참조 가능
7101← 그런데 이 두 번째 줄을 외래키는 막지 못합니다
같은 사람이 같은 글에 좋아요를 두 번 남긴 상태 — FK 는 아무 문제도 못 느낍니다

같은 사용자가 같은 글에 좋아요를 두 번 저장하지 못하게 하려면 “이 두 번호의 조합은 중복될 수 없다” 는 규칙이 따로 필요합니다. (user_id, post_id) 조합에 거는 유일성 제약이죠.

사실 우리 shop 에 이미 있습니다

order_items 의 기본키는 (order_id, product_id) 복합키입니다. 그래서 같은 주문에 같은 상품이 두 줄로 들어가는 일이 구조적으로 막혀 있어요. 좋아요 중복 금지와 정확히 같은 원리입니다.

팔로우는 한술 더 뜹니다. follows 테이블에 follower_idfollowing_id가 나란히 있고 둘 다 users를 참조한다고 해볼게요.

가상 예시 — follows 에서 FK 가 못 막는 것
저장하려는 행외래키 판정실제 업무에서는
follower 7 → following 12통과정상
follower 7 → following 7통과 (7번은 실존 사용자)자기 자신 팔로우 — 막아야 함
follower 7 → following 12 (또)통과같은 사람 두 번 팔로우 — 막아야 함
두 번호 모두 실존하는 사용자이기만 하면 외래키는 통과시킵니다

관계선이 보여주지 않는 규칙 ② — 시간

객실 예약도 마찬가지입니다. 회원과 객실을 reservations 테이블로 연결하면 누가 어느 객실을 예약했는지는 표현됩니다. 그런데 예약 업무의 진짜 규칙은 대부분 시간에 있어요.

가상 예시 — reservations 에서 선 밖에 남는 규칙
업무 규칙관계선·외래키로 되는가
시작 시각 < 종료 시각아니오 — 두 값 사이의 조건이라 선과 무관
같은 객실의 두 예약은 시간이 겹치면 안 된다아니오 — 다른 행과 비교해야 알 수 있다
이미 지난 시각으로는 예약할 수 없다아니오 — 지금 시각과 비교해야 한다
존재하지 않는 객실·회원은 예약할 수 없다예 — 이건 외래키가 막아 줍니다
FK 가 막아 주는 건 마지막 한 줄뿐입니다

특히 시간 겹침은 성격이 다릅니다. 한 행만 봐서는 옳고 그름을 판단할 수 없고, 같은 객실의 다른 예약들과 비교해야만 알 수 있으니까요.

어떤 규칙을 어디서 막는가
규칙의 성격막는 곳가상 예시
연결 대상이 실제로 존재하는가외래키 (FK)reservations.room_id → rooms
같은 조합이 두 번 들어오지 않는가유일성 제약 (UNIQUE · 복합 PK)(user_id, post_id) 좋아요 중복 금지
한 행 안의 값들이 말이 되는가행 조건 검사 (CHECK)시작 시각 < 종료 시각
다른 행·현재 시각과 비교해야 하는가애플리케이션 로직 · 트랜잭션같은 객실 시간 겹침 · 과거 시각 예약
MySQL 은 8.0.16 부터 CHECK 제약이 실제로 동작합니다 — 그 전 버전에서는 문법만 받고 무시했어요
⭐ 오늘의 마지막 문장

ERD의 선은 누가 누구와 연결되는지를 보여줍니다. 중복 금지나 시간 충돌처럼 선만으로 부족한 규칙은 글과 제약으로 따로 남겨야 합니다.

ERD를 다 그린 뒤에 “이 그림에 안 적힌 규칙은 무엇인가?” 를 한 번 물어보세요. 실무에서 사고는 대부분 그 빈칸에서 납니다.

분석을 끝내기 전 세 가지 질문

ERD 경로를 따라간 뒤 반드시 확인할 것
① 지금 한 행은 무엇인가? — 회원인가, 주문인가, 주문상세인가
② 행을 셀 것인가, 행 안의 값을 더할 것인가? — 10행과 11개는 다르다
③ 같은 대상의 중복을 그대로 둘 것인가, 뺄 것인가? — 6행과 4명은 다르다

여기에 하나만 더 붙이면 분석이 끝납니다. 관계선만으로 막지 못하는 업무 규칙은 무엇인가.

한눈에 정리

물어볼 것왜 묻는가오늘 확인한 것
지금 한 행은?관계를 지날 때마다 단위가 바뀐다shop — 회원 1행 → 주문 6행 → 주문상세 10행
셀까, 더할까?행 수와 수량 합계는 단위가 다르다shop — 주문상세 10행 ≠ 수량 합계 11개
중복을 뺄까?거슬러 올라가면 같은 대상이 반복된다shop — 상품 23번 → 상세 6행, 서로 다른 회원 4명
선 밖의 규칙은?FK 는 연결만 보장한다가상 예시 — 중복 금지 · 시간 겹침 · 과거 예약

ERD의 길을 따라갈 때마다 지금 한 행이 무엇인지, 중복을 뺄지, 관계선 밖에 남은 규칙은 무엇인지를 다시 묻습니다. 이 세 가지만 습관이 되면 처음 보는 ERD 앞에서도 무엇부터 봐야 할지 알게 돼요.

이제 남은 건 하나입니다. 읽고 분석했으니 — 직접 그려 볼 차례예요.

NEXT LESSON4-7 모델링 종합 실습 — 요구사항에서 ERD까지 ⭐

상품 후기 기능을 요구사항 질문부터 시작해 한 행·키·관계·제약까지 직접 설계하고 검산합니다.

GO ▸ 4-7 시작하기