topic난이도 · 약 20

정규화 · 관계(1:N·N:M) · ERD

1NF/2NF/3NF · 외래키 · 1:N과 N:M · 반정규화 트레이드오프 — 스키마 설계의 뼈대.

#정규화#1NF#2NF#3NF#ERD#N:M#외래키
왜 배우는가

AI에게 "DB 스키마 짜줘"라고 하면 잘못된 정규화로 중복·이상(anomaly)이 생기기 쉽다. 1:N·N:M을 구분할 줄 알면 엉성한 스키마를 바로잡을 수 있다.

정규화는 중복을 제거해 이상(anomaly)을 막는 설계 원칙. 삽입·갱신·삭제 시 모순이 나지 않게 테이블을 적절히 쪼갠다.

단계규칙어기면?
1NF한 칸에 값 하나 (원자성)`tags = "js,ts"` 같은 CSV 지옥
2NF1NF + 부분 함수 종속 제거복합키 일부에만 의존
3NF2NF + 이행 종속 제거비키 속성이 다른 비키에 의존
실무3NF까지만 기본그 이상은 보통 과도함
sql
-- ❌ 비정규화 (나쁜 예)
CREATE TABLE orders (
  id INT PRIMARY KEY,
  customer_name TEXT,     -- 고객 정보 중복 저장
  customer_email TEXT,    -- 고객이 이메일 바꾸면 모든 주문 업데이트
  items TEXT              -- "책|펜|노트" CSV 지옥
);

-- ✅ 정규화된 설계
CREATE TABLE customers (
  id SERIAL PRIMARY KEY,
  name TEXT NOT NULL,
  email TEXT UNIQUE NOT NULL
);

CREATE TABLE orders (
  id SERIAL PRIMARY KEY,
  customer_id INT NOT NULL REFERENCES customers(id),
  created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE order_items (          -- 1:N (주문 1개 → 아이템 N개)
  id SERIAL PRIMARY KEY,
  order_id INT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
  product_id INT NOT NULL REFERENCES products(id),
  quantity INT NOT NULL
);

ON DELETE CASCADE — 주문 삭제 시 관련 아이템도 자동 삭제. 참조 무결성 유지의 표준 도구.

관계예시스키마 표현
1:1사용자-프로필`user_profiles.user_id UNIQUE REFERENCES users(id)`
1:N유저-주문`orders.user_id REFERENCES users(id)`
N:M학생-수업조인 테이블 (`enrollments(student_id, course_id)`)
sql
-- N:M 관계 (학생 ↔ 수업) — 조인 테이블 필수
CREATE TABLE students (id SERIAL PK, name TEXT);
CREATE TABLE courses  (id SERIAL PK, title TEXT);

CREATE TABLE enrollments (
  student_id INT REFERENCES students(id),
  course_id  INT REFERENCES courses(id),
  enrolled_at TIMESTAMPTZ DEFAULT NOW(),
  PRIMARY KEY (student_id, course_id)        -- 복합키 = 중복 수강 방지
);

-- "학생 A가 듣는 모든 수업"
SELECT c.title
FROM students s
JOIN enrollments e ON s.id = e.student_id
JOIN courses c ON c.id = e.course_id
WHERE s.id = ?;

"한 학생은 여러 수업, 한 수업은 여러 학생" — 이 둘을 합친 게 N:M. 조인 테이블 없이 CSV로 저장하면 확장 시 지옥.

반정규화(Denormalization) — 조회 성능을 위해 일부러 중복 저장. 예: `users.post_count`를 미리 저장. 장점: JOIN·COUNT 불필요. 단점: 업데이트 시 동기화 책임. 초반엔 정규화, 느려지면 선택적 반정규화.

ERD(Entity-Relationship Diagram)는 테이블·관계를 그림으로. Claude에게 "이 요구사항의 ERD 그려줘" → Mermaid나 ASCII로 받을 수 있다. 초기 설계 리뷰에 필수.

text
# Mermaid ERD (Claude가 자주 뽑는 포맷)
erDiagram
  users ||--o{ orders : "places"
  orders ||--|{ order_items : "contains"
  products ||--o{ order_items : "included in"

  users { int id PK; text name; text email }
  orders { int id PK; int user_id FK; timestamp created_at }
  order_items { int id PK; int order_id FK; int product_id FK; int qty }
  products { int id PK; text name; numeric price }

`||--o{` = 1:N, `}o--o{` = N:M, PK = 기본키, FK = 외래키. GitHub·Notion에서 그대로 렌더링.

실기 드릴 2문항
edit실기 드릴 · 단답형

학생과 수업처럼 '다대다' 관계를 표현할 때 필요한 별도 테이블의 이름은?

check_circle실기 드릴 · OX

반정규화는 항상 나쁜 설계다.