ER 다이어그램 읽기와 그리기
Chen 표기법과 Crow's Foot 표기법을 비교하고, 엔티티·속성·관계·기수성(Cardinality) 개념을 쇼핑몰 도메인 ERD 예시와 함께 설명합니다.
지난 글에서 비정규화 결정 기준을 살펴봤다. 이번에는 데이터베이스 설계의 출발점인 ER 다이어그램(Entity-Relationship Diagram)을 읽고 그리는 방법을 정리한다.
ERD가 필요한 이유
ERD는 비즈니스 도메인을 테이블로 옮기기 전에 개념 수준에서 엔티티와 관계를 그림으로 표현한다. 코드가 아니라 그림이기 때문에 개발자, DBA, 기획자가 같은 언어로 소통할 수 있다.
핵심 구성 요소
엔티티(Entity)
실세계에서 독립적으로 식별 가능한 객체. 테이블에 대응한다.
강한 엔티티(Strong Entity): 독립적으로 존재 — CUSTOMER, PRODUCT
약한 엔티티(Weak Entity): 강한 엔티티 없이 존재 불가 — ORDER_ITEM
속성(Attribute)
엔티티가 갖는 성질. 컬럼에 대응한다.
단순 속성: name, email (더 이상 분해 안 됨)
복합 속성: address = {city, street, zipcode} (분해 가능)
다치 속성: phone_numbers (여러 값 가질 수 있음) → 별도 테이블로
파생 속성: age (birth_date로 계산) → 일반적으로 저장 안 함
관계(Relationship)
엔티티 간의 연관. FK로 구현된다.
CUSTOMER --[PLACES]--> ORDER
ORDER --[CONTAINS]--> ORDER_ITEM
ORDER_ITEM --[INCLUDES]--> PRODUCT
표기법 비교
Chen 표기법은 엔티티를 직사각형, 속성을 타원, 관계를 마름모로 표현한다. 개념 설계 단계에서 관계의 의미를 명확히 드러낼 때 유용하다.
Crow’s Foot(IE 표기법)은 엔티티 박스 안에 속성을 직접 나열하고, 연결선 끝에 기수성을 표기한다. 실무 ERD 도구(ERDCloud, dbdiagram.io, Mermaid)의 기본값이다.
기수성(Cardinality)
두 엔티티 간에 몇 대 몇으로 관계를 맺는지를 나타낸다.
| 관계 | 의미 | 예시 |
|---|---|---|
| 1:1 | 양쪽 모두 정확히 1 | 사원 ↔ 주차번호 |
| 1:N | 하나가 여럿에 대응 | 고객 → 주문 |
| N:M | 양쪽 모두 여럿 | 학생 ↔ 강의 |
N:M 관계는 교차 테이블(Junction Table)로 분해해야 물리 구현이 가능하다.
-- N:M 예시: 학생-강의
CREATE TABLE student_course (
student_id INT REFERENCES students(id),
course_id INT REFERENCES courses(id),
enrolled_at DATE,
PRIMARY KEY (student_id, course_id)
);
쇼핑몰 도메인 ERD 예시
위 ERD를 SQL DDL로 옮기면 다음과 같다.
CREATE TABLE customers (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
phone VARCHAR(20),
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
grade CHAR(1) NOT NULL DEFAULT 'B' -- A/B/C/D
);
CREATE TABLE orders (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
customer_id BIGINT NOT NULL REFERENCES customers(id),
status VARCHAR(20) NOT NULL DEFAULT 'pending',
total_amount NUMERIC(12,2) NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
shipped_at TIMESTAMPTZ
);
CREATE TABLE products (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
name VARCHAR(200) NOT NULL,
price NUMERIC(10,2) NOT NULL,
stock INT NOT NULL DEFAULT 0,
category_id INT REFERENCES categories(id)
);
CREATE TABLE order_items (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
order_id BIGINT NOT NULL REFERENCES orders(id),
product_id BIGINT NOT NULL REFERENCES products(id),
qty INT NOT NULL CHECK (qty > 0),
unit_price NUMERIC(10,2) NOT NULL -- 주문 당시 가격 스냅샷
);
필수 vs 선택 참여
기수성 외에 참여 제약(Participation Constraint)도 표기해야 한다.
전체 참여(Mandatory): 모든 고객은 반드시 주문을 가져야 한다
부분 참여(Optional): 고객이 주문을 가질 수도, 없을 수도 있다
Crow’s Foot에서는 |O≫ 기호로 표기한다: |는 “정확히 1”, O는 “0 가능”, ≫는 “다수”.
-- 참여 제약 → NOT NULL로 구현
-- 주문은 반드시 고객을 가져야 함: customer_id NOT NULL
-- 주문에 배송 주소는 선택: address_id NULL 허용
ERD 작성 순서
- 도메인 분석: 무엇이 엔티티인가 (명사 추출)
- 관계 식별: 엔티티 간 동사 도출
- 기수성 결정: 1:1, 1:N, N:M 판별
- 속성 배치: 기본키, 외래키, 일반 속성
- 정규화 검토: 중복·이상 현상 확인
- DDL 생성: ERD → SQL CREATE TABLE
지난 글: 비정규화 결정 기준
다음 글: 관계 매핑: ERD를 테이블로 변환하기
읽어주셔서 감사합니다. 😊