모든 강의를 무료로 볼 수 있어요. 회원가입 없이도 학습 가능합니다.

23강 / 전체 24강

데이터 모델링 기초

8분 읽기 조회 0

ER 다이어그램으로 개체·관계를 파악하고, 1:N·M:N 관계를 테이블로 표현하며, 정규화의 핵심 직관을 익힙니다.

🎯 학습 목표

이 강을 마치면 ER 다이어그램(ERD)을 읽고 개체와 관계를 파악할 수 있습니다. 1:1, 1:N, M:N 세 가지 관계를 테이블로 변환하는 방법을 이해하고, 중간 테이블(연결 테이블)이 M:N 관계를 어떻게 해소하는지 설명할 수 있게 됩니다. 정규화의 핵심 직관인 "한 가지 사실은 한 곳에만"도 이해할 수 있습니다.

💡 데이터 모델링이란

이 섹션에서는 데이터 모델링의 개념과 필요한 이유를 살펴보겠습니다.

데이터 모델링(Data Modeling)은 현실 세계의 개념과 규칙을 데이터베이스 구조로 표현하는 과정입니다. "온라인 서점에서 회원이 도서를 주문한다"는 현실을 members, books, orders 세 테이블로 표현한 것이 바로 데이터 모델링의 결과입니다.

좋은 데이터 모델이 있어야 쿼리가 쉬워지고, 데이터 중복이 줄고, 변경에 유연해집니다. 반대로 모델이 잘못되면 아무리 뛰어난 SQL 실력이 있어도 복잡하고 느린 쿼리로 고생하게 됩니다. 개발을 시작하기 전 "어떤 테이블을 만들고, 어떻게 연결할 것인가"를 설계하는 시간이 반드시 필요한 이유입니다.

📐 ERD — 개체-관계 다이어그램

이 섹션에서는 ERD의 구성 요소와 읽는 방법을 살펴보겠습니다.

ERD(Entity-Relationship Diagram)는 데이터 모델을 시각적으로 표현한 다이어그램입니다. 세 가지 핵심 요소로 구성됩니다.

개체(Entity)는 데이터를 저장해야 하는 대상입니다. 회원, 도서, 주문, 카테고리, 리뷰 등이 개체이며, 각각 테이블이 됩니다. ERD에서 직사각형으로 표현합니다.

속성(Attribute)은 개체가 가진 특성입니다. 회원의 속성은 회원번호, 이름, 이메일, 등급, 가입일입니다. 이것이 테이블의 열이 됩니다. ERD에서 타원 또는 개체 상자 안의 항목으로 표현합니다.

관계(Relationship)는 개체 간의 연관을 표현합니다. "회원이 도서를 주문한다"는 관계입니다. ERD에서 마름모 또는 선으로 연결해 표현하며, 관계의 개수(카디널리티)를 표시합니다.

온라인 서점 ERD를 텍스트로 표현하면 다음과 같습니다.

-- ERD 개념을 CREATE TABLE로 표현
-- [members] --1:N-- [orders] --N:1-- [books]
--
-- members: member_id(PK), name, email, grade, join_date
-- books:   book_id(PK), title, author, price, stock, category
-- orders:  order_id(PK), member_id(FK→members), book_id(FK→books),
--          quantity, order_date, status

🔢 세 가지 관계 유형

이 섹션에서는 1:1, 1:N, M:N 세 가지 관계를 테이블로 표현하는 방법을 살펴보겠습니다.

1:1 관계(One-to-One)는 한 개체가 다른 개체와 정확히 하나씩 연결됩니다. 예를 들어 회원(member)과 회원 상세 정보(member_detail)가 1:1이라면, 두 테이블을 합칠 수도 있고, 자주 조회하지 않는 컬럼을 분리해 성능을 높이기 위해 나눌 수도 있습니다.

-- 1:1 관계: member_detail에 member_id를 PK이자 FK로 설정
CREATE TABLE member_detail (
  member_id   INTEGER  PRIMARY KEY,
  address     TEXT,
  birth_date  TEXT,
  FOREIGN KEY (member_id) REFERENCES members(member_id)
);

1:N 관계(One-to-Many)는 가장 일반적인 관계입니다. 한 회원이 여러 주문을 가집니다(1:N). N 쪽 테이블(orders)에 1 쪽 테이블(members)의 기본키를 외래키로 보관합니다. 우리 실습 DB가 이 구조입니다.

-- 1:N 관계: N 쪽에 외래키
-- members (1) ──< orders (N)
-- orders.member_id → members.member_id

M:N 관계(Many-to-Many)는 두 개체가 서로 여러 개와 연결됩니다. 예를 들어 도서는 여러 태그를 가질 수 있고, 태그도 여러 도서에 붙을 수 있습니다. M:N 관계는 테이블로 직접 표현할 수 없습니다. 중간 테이블(Junction Table, Associative Table)을 만들어 두 개의 1:N 관계로 분해합니다.

-- M:N 관계 해소: 도서-태그 예시
CREATE TABLE tags (
  tag_id   INTEGER  PRIMARY KEY,
  tag_name TEXT     NOT NULL UNIQUE
);

-- 중간 테이블 (book_tags)
CREATE TABLE book_tags (
  book_id  INTEGER  NOT NULL,
  tag_id   INTEGER  NOT NULL,
  PRIMARY KEY (book_id, tag_id),  -- 복합 기본키
  FOREIGN KEY (book_id) REFERENCES books(book_id) ON DELETE CASCADE,
  FOREIGN KEY (tag_id)  REFERENCES tags(tag_id)   ON DELETE CASCADE
);

-- 도서-태그 연결 예시
INSERT INTO tags VALUES (1, 'SQL'), (2, '입문'), (3, '데이터베이스');
INSERT INTO book_tags VALUES (1, 1), (1, 2), (1, 3);  -- 'SQL 첫걸음'에 세 태그

중간 테이블은 두 외래키를 복합 기본키로 가집니다. 같은 (book_id, tag_id) 조합이 중복되는 것을 방지합니다. 중간 테이블에 추가 속성(예: 태그를 붙인 날짜, 추가한 사용자)도 가질 수 있습니다.

🧹 정규화의 핵심 직관

이 섹션에서는 데이터 중복을 줄이는 정규화의 핵심 원칙을 살펴보겠습니다.

정규화(Normalization)는 데이터 중복을 제거하고 갱신 이상을 방지하는 테이블 설계 원칙입니다. 학문적으로 1NF, 2NF, 3NF, BCNF 같은 정규형이 있지만, 입문 단계에서는 핵심 직관 두 가지를 이해하면 충분합니다.

첫 번째 직관은 "한 가지 사실은 한 곳에만 저장한다"입니다. 도서 가격이 books 테이블에 있는데, orders 테이블에도 같이 저장했다면 가격이 바뀔 때 두 곳을 동시에 수정해야 합니다. 하나라도 빠뜨리면 데이터 불일치가 생깁니다. 가격은 books 테이블에만 두고, orders에서 필요하면 JOIN으로 가져옵니다.

두 번째 직관은 "어떤 열의 값이 다른 열에 의존하면 별도 테이블로 분리한다"입니다. 만약 orders에 category(도서 카테고리)가 있다면, category는 book_id에 의존합니다. book_id가 같으면 category도 같아야 합니다. 이런 의존성은 category를 books 테이블로 이동시키라는 신호입니다.

실습 DB를 확인해봅니다. books에 category가 있고 orders에는 없습니다. 주문에서 카테고리가 필요하면 books와 JOIN해서 가져옵니다. 이것이 올바른 설계입니다.

⚖️ 정규화 vs 비정규화

이 섹션에서는 정규화의 트레이드오프와 비정규화가 선택되는 상황을 살펴보겠습니다.

정규화를 완전히 적용하면 중복이 없고 데이터 일관성이 높아지지만, 많은 JOIN이 필요해 쿼리가 복잡해지고 성능이 떨어질 수 있습니다.

비정규화(Denormalization)는 의도적으로 중복을 허용해 성능을 높이는 기법입니다. 예를 들어 주문 완료 시 도서 가격을 orders 테이블에 기록해 두면, 나중에 도서 가격이 바뀌어도 주문 당시 가격을 정확히 알 수 있습니다. 이것은 "과거의 사실을 기록"하는 이력 관리 목적의 비정규화입니다.

-- 비정규화 예시: 주문 당시 가격을 함께 기록
CREATE TABLE orders_denorm (
  order_id    INTEGER  PRIMARY KEY AUTOINCREMENT,
  member_id   INTEGER  NOT NULL,
  book_id     INTEGER  NOT NULL,
  unit_price  INTEGER  NOT NULL,  -- 주문 당시 가격 기록 (비정규화)
  quantity    INTEGER  NOT NULL,
  order_date  TEXT     NOT NULL DEFAULT (date('now')),
  status      TEXT     NOT NULL DEFAULT 'PENDING'
);

현재 books.price가 변해도 orders_denorm.unit_price는 주문 당시 가격을 보존합니다. 이런 선택은 비즈니스 요구사항에 따라 정당화됩니다. "정규화가 무조건 옳다"는 아닙니다. 상황에 따라 판단합니다.

📝 핵심 요약

이번 강에서 배운 내용을 정리하겠습니다.

개념핵심
ERD개체(테이블)·속성(열)·관계(외래키)를 시각화
1:1 관계N 쪽에 FK — 보통 같은 PK를 FK로 사용
1:N 관계N 쪽 테이블에 1 쪽의 PK를 FK로 보관
M:N 관계중간 테이블로 두 개의 1:N으로 분해
정규화 직관한 가지 사실은 한 곳에만 / 의존성 있으면 분리
비정규화이력 관리·성능 목적으로 의도적 중복 허용

데이터 모델링은 SQL 문법 밖의 영역이지만, 좋은 쿼리를 작성하려면 좋은 모델이 기반이 되어야 합니다. 이 강을 마지막으로 핵심 이론을 모두 배웠습니다. 다음 24강에서는 이 강좌 전체를 마무리하며 실전에서 SQL을 계속 발전시키는 방법, 다음 학습 경로, 그리고 자주 쓰는 SQL 패턴 치트시트를 정리합니다.

관련 주제

  • ER 다이어그램
  • ERD
  • 1:1 관계
  • 1:N 관계
  • M:N 관계
  • 중간 테이블
  • 정규화 직관
  • 개발·프로그래밍
  • 개발·프로그래밍 강의
  • SQL·데이터베이스 입문 24강
  • 무료강의
  • 무료 온라인 강의
  • NUGUNA
  • 누구나

📚 시리즈 전체 공유

SQL·데이터베이스 입문 24강

이 강의가 속한 시리즈는 총 24강, 모두 무료입니다. 처음부터 배우려는 동료에게 시리즈 전체를 알려 주세요.

댓글

0/1000

불러오는 중...