ERD 표기법과 실습
ER 모델을 그림으로 표현하는 방식이 ERD(Entity-Relationship Diagram)입니다. 표기법에 따라 같은 모델도 다르게 보이므로, 대표적인 표기법들을 알아두면 어디서든 ERD를 읽고 그릴 수 있습니다. 이 절에서는 Chen, IE(Crow's Foot), UML 표기법을 비교한 뒤, 실무 도구 활용과 단계별 설계 실습을 진행합니다.
첸(Chen) 표기법
피터 첸(Peter Chen)이 1976년에 제안한 원래의 ER 다이어그램 표기법입니다. 학술적인 자료와 시험 문제에서 자주 등장하며, 개념적 모델링에 적합합니다.
┌──────────────────────────────────────────────────────────┐
│ Chen 표기법 기호 일람 │
├──────────────────────────────────────────────────────────┤
│ │
│ ┌───────────┐ │
│ │ 개체 │ → 사각형 (Strong Entity) │
│ └───────────┘ │
│ │
│ ╔═══════════╗ │
│ ║ 약한 개체 ║ → 이중 사각형 (Weak Entity) │
│ ╚═══════════╝ │
│ │
│ ◇ 관계 → 마름모 (Relationship) │
│ ◆ 식별 관계 → 이중 마름모 (Identifying Relationship) │
│ │
│ ○ 속성 → 타원 (Attribute) │
│ ◎ 다중값 속성 → 이중 타원 (Multi-valued Attribute) │
│ -- 파생 속성 → 점선 타원 (Derived Attribute) │
│ _밑줄_ 속성 → 키 속성 (Key Attribute) │
│ │
│ 카디널리티: 1, N, M 숫자로 표기 │
│ 참여 제약: 단선(부분 참여), 이중선(전체 참여) │
│ │
└──────────────────────────────────────────────────────────┘ ○학번(PK) ○이름 ○학과
│ │ │
┌────────┴─────────┴────────┴────────┐
│ 학생 │
└─────────────────┬──────────────────┘
│ N
│
◇ 수강하다
│
│ M
┌─────────────────┴──────────────────┐
│ 과목 │
└────────┬─────────┬─────────────────┘
│ │
○과목코드 ○과목명
(PK)
학생 N ── M 과목 (다대다 관계)
→ 수강 관계에 '성적' 속성이 붙을 수 있음 ┌──────────────┐ ╔══════════════╗
│ 건물 │ ║ 강의실 ║
└──────┬───────┘ ╚══════┬═══════╝
│ 1 │ N
│ │
└────────── ◆ ──────────────┘
소속(식별 관계)
약한 개체 '강의실'
* 건물 없이는 독립적으로 존재할 수 없음
* 식별자: {건물코드(FK)} + 호수(부분키)
* 이중 사각형 + 이중 마름모로 표시첸 표기법은 개체·관계·속성이 명확하게 분리되므로 학습과 시험에 유용합니다. 하지만 속성이 많아지면 다이어그램이 매우 복잡해지는 단점이 있어 실무에서는 잘 쓰이지 않습니다.
까마귀 발(Crow's Foot / IE) 표기법
실무에서 가장 널리 사용되는 표기법입니다. IE(Information Engineering) 표기법이라고도 합니다. 관계의 차수를 선의 끝 모양으로 표현하며, 속성을 개체 박스 안에 넣어 공간을 절약합니다.
끝 기호(Notation)
──│ 1 (정확히 하나) 세로선
──○ 0 (없을 수도 있음) 동그라미
──< N (다수, Many) 까마귀 발
조합 — 최소..최대
──│──│ 1..1 정확히 하나 (필수, 단일)
──○──│ 0..1 없거나 하나 (선택, 단일)
──│──< 1..N 하나 이상 (필수, 다수)
──○──< 0..N 없거나 여러 개 (선택, 다수)┌──────┐ ┌──────┐
│ 부서 │──│──────○──<──│──│ 사원 │
└──────┘ └──────┘
왼쪽에서 오른쪽으로 읽기
부서 쪽 기호: │ (정확히 하나)
→ "사원은 반드시 하나의 부서에 속한다"
사원 쪽 기호: ○──< (0 이상)
→ "부서에는 사원이 없을 수도, 여러 명일 수도 있다"
읽는 방향: 화살표 반대쪽에서 읽는다
"부서 입장에서 사원은 0..N"
"사원 입장에서 부서는 1..1"┌──────────┐ ┌──────────┐ ┌───────────┐
│ 회원 │ │ 주문 │ │ 주문상세 │
├──────────┤ ├──────────┤ ├───────────┤
│ *id (PK)│ │ *id (PK)│ │ *id (PK) │
│ name │──│──○──<─│ user_id │─>──│──<──│ order_id │
│ email │ │ date │ │ prod_id │
│ phone │ │ status │ │ qty │
└──────────┘ │ total │ │ price │
└──────────┘ └───────────┘
* PK는 *로 표시 (관례)
* FK는 참조 테이블로 연결선Crow's Foot 표기법은 테이블 구조에 가까운 형태이므로, 논리적·물리적 모델링에 적합합니다.
식별 / 비식별 관계
Crow's Foot 표기법에서는 관계선의 종류로 식별/비식별 관계를 구분합니다.
식별 관계 (Identifying)
──────── 실선
* 부모의 PK가 자식의 PK에 포함
* 예: 주문(PK: 주문ID) → 주문상세(PK: {주문ID, 상품ID})
* 부모 없이 자식 존재 불가
비식별 관계 (Non-Identifying)
- - - - 점선
* 부모의 PK가 자식의 일반 컬럼(FK)으로만 존재
* 예: 부서(PK: 부서ID) → 사원(PK: 사원ID, FK: 부서ID)
* 부모 없이도 자식 존재 가능 (NULL 허용 시)
실무 선택 기준
┌──────────────────────────────────────────────────┐
│ 식별 관계 사용 │
│ * 부모-자식 생명주기가 같을 때 │
│ * 주문 ↔ 주문상세, 게시글 ↔ 첨부파일 │
│ │
│ 비식별 관계 사용 │
│ * 참조만 할 때, 독립성이 필요할 때 │
│ * 사원 ↔ 부서, 게시글 ↔ 작성자 │
│ * 대부분의 실무 관계는 비식별 │
└──────────────────────────────────────────────────┘UML 클래스 다이어그램 표기법
UML(Unified Modeling Language)의 클래스 다이어그램도 ER 모델 표현에 사용됩니다. 객체지향 설계에서 ER 모델을 겸할 때 유용합니다.
UML 다중성 표기
1 정확히 1
0..1 0 또는 1
* 0 이상 (0..*)
1..* 1 이상
3..5 3 이상 5 이하
비교
┌──────────────┬────────────────┬───────────┐
│ 의미 │ Crow's Foot │ UML │
├──────────────┼────────────────┼───────────┤
│ 정확히 하나 │ ──│──│ │ 1 │
│ 0 또는 하나 │ ──○──│ │ 0..1 │
│ 하나 이상 │ ──│──< │ 1..* │
│ 0 이상 │ ──○──< │ 0..* (*) │
└──────────────┴────────────────┴───────────┘┌─────────────────┐ ┌─────────────────┐
│ <<entity>> │ │ <<entity>> │
│ User │ │ Order │
├─────────────────┤ ├─────────────────┤
│ - id: int {PK} │ │ - id: int {PK} │
│ - name: varchar │ 1 * │ - userId: int │
│ - email: varchar│──────────│ - date: date │
│ │ places │ - total: decimal│
├─────────────────┤ ├─────────────────┤
│ + getOrders() │ │ + getItems() │
└─────────────────┘ └─────────────────┘
* 3단 박스: 클래스명 / 속성 / 메서드
* 관계선에 역할 이름(places) 표기
* 다중성을 양쪽 끝에 숫자로 명시3대 표기법 비교
┌───────────────┬────────────┬────────────┬────────────┐
│ 항목 │ Chen │ Crow's Foot│ UML │
├───────────────┼────────────┼────────────┼────────────┤
│ 개체 표현 │ 사각형 │ 박스+속성 │ 3단 박스 │
│ 속성 표현 │ 타원(외부) │ 박스 내부 │ 박스 내부 │
│ 관계 표현 │ 마름모 │ 연결선 │ 연결선 │
│ 카디널리티 │ 1, N, M │ 끝 기호 │ 숫자 범위 │
│ 장점 │ 개념 명확 │ 실무 직관 │ OOP 통합 │
│ 단점 │ 공간 과다 │ 개념 혼동 │ DB 전용X │
│ 사용 상황 │ 학습/시험 │ DB 실무 │ 객체지향 │
│ 대표 도구 │ 교재/논문 │ ERDCloud │ StarUML │
└───────────────┴────────────┴────────────┴────────────┘ERD 도구
| 도구 | 특징 | 비용 |
|---|---|---|
| ERDCloud | 웹 기반, 한국어, 공유·협업 기능 | 무료 |
| dbdiagram.io | 코드로 ERD 작성, 깔끔한 UI | 무료/유료 |
| MySQL Workbench | MySQL 리버스 엔지니어링 지원 | 무료 |
| Oracle SQL Developer Data Modeler | Oracle 특화, 포워드/리버스 엔지니어링 | 무료 |
| draw.io (diagrams.net) | 범용 다이어그램, ERD 템플릿 제공 | 무료 |
| Lucidchart | 협업 기능 강력, 클라우드 기반 | 유료 |
| DataGrip (JetBrains) | DB IDE에 내장된 ERD 시각화 | 유료 |
| DBeaver | 오픈소스 DB 도구, ERD 자동 생성 | 무료/유료 |
dbdiagram.io 문법
dbdiagram.io에서는 코드로 테이블을 정의하면 자동으로 ERD가 생성됩니다. DBML(Database Markup Language)이라는 DSL을 사용합니다.
Table users {
id int [pk, increment]
name varchar [not null]
email varchar [unique, not null]
created_at timestamp [default: `now()`]
}
Table orders {
id int [pk, increment]
user_id int [ref: > users.id] // Many-to-One
total_amount decimal
status enum('pending','paid','shipped')
order_date date
}
Table order_items {
id int [pk, increment]
order_id int [ref: > orders.id]
product_id int [ref: > products.id]
quantity int [not null]
unit_price decimal [not null]
}
Table products {
id int [pk, increment]
name varchar [not null]
price decimal [not null]
category_id int [ref: > categories.id]
stock int [default: 0]
}
Table categories {
id int [pk, increment]
name varchar [not null]
parent_id int [ref: > categories.id] // Self-reference
}
// DBML 관계 표기
// > Many-to-One
// < One-to-Many
// - One-to-One
// <> Many-to-ManyERDCloud 활용
ERDCloud는 한국어를 지원하는 웹 기반 ERD 도구로, 직관적인 드래그 앤 드롭 인터페이스를 제공합니다.
┌──────────────────────────────────────────────────┐
│ ERDCloud 기능 정리 │
├──────────────────────────────────────────────────┤
│ │
│ 테이블 생성 │
│ * 드래그 앤 드롭으로 개체 배치 │
│ * 속성 추가 시 PK/FK/NN/UQ 설정 │
│ * 데이터 타입 직접 지정 │
│ │
│ 관계 설정 │
│ * 식별/비식별 관계 선택 │
│ * 카디널리티 자동 표시 │
│ * 관계선 드래그로 연결 │
│ │
│ 내보내기 │
│ * DDL 자동 생성 (MySQL, PostgreSQL, Oracle) │
│ * 이미지 내보내기 (PNG, SVG) │
│ * JSON 형식 내보내기 │
│ │
│ 협업 │
│ * URL 공유 │
│ * 팀 워크스페이스 │
│ * 버전 관리 │
│ │
└──────────────────────────────────────────────────┘ERD 개체·속성·관계 매핑 규칙
ERD에서 릴레이션으로 변환할 때의 기본 규칙을 미리 정리합니다.
1. 강한 개체 → 테이블
* 모든 단순 속성 → 컬럼
* 키 속성 → PK 컬럼
* 복합 속성 → 하위 속성만 컬럼으로
2. 약한 개체 → 테이블
* 소유 개체의 PK를 FK로 포함
* PK = 소유 개체 PK + 부분키
3. 1:1 관계
* 한쪽 테이블에 FK 추가 (전체 참여 쪽에)
* 또는 별도 관계 테이블 (드물게)
4. 1:N 관계
* N쪽 테이블에 1쪽의 PK를 FK로 추가
5. M:N 관계
* 별도 관계(교차) 테이블 생성
* 양쪽 PK를 FK로 포함 → 복합키 또는 대리키
6. 다중값 속성
* 별도 테이블로 분리
* 원래 개체의 PK를 FK로 포함
7. 파생 속성
* 저장하지 않거나 (계산)
* 성능을 위해 저장 (반정규화)실습 1 — 온라인 쇼핑몰 ERD
쇼핑몰의 요구사항을 분석하고 ERD를 단계별로 설계합니다.
1. 회원은 이름, 이메일, 전화번호, 주소를 가진다
2. 상품은 이름, 가격, 재고를 가지며 카테고리에 속한다
3. 회원은 여러 주문을 할 수 있다
4. 하나의 주문에 여러 상품이 포함된다 (수량, 단가 기록)
5. 카테고리는 계층 구조이다 (대분류 > 중분류 > 소분류)
6. 회원은 상품에 리뷰를 남길 수 있다 (별점, 내용)
7. 배송 정보를 기록한다 (배송상태, 운송장번호, 배송업체)개체(Entity)
* 회원(User) — 서비스 이용 주체
* 상품(Product) — 판매 대상
* 카테고리(Category) — 상품 분류
* 주문(Order) — 구매 행위
* 주문상세(OrderItem)— 주문-상품 교차
* 리뷰(Review) — 상품 평가
* 배송(Shipping) — 배송 정보관계
회원 ──(1:N)── 주문 : 한 회원이 여러 주문
주문 ──(1:N)── 주문상세 : 한 주문에 여러 상품
상품 ──(1:N)── 주문상세 : 한 상품이 여러 주문에 포함
카테고리 ──(1:N)── 상품 : 한 카테고리에 여러 상품
카테고리 ──(자기참조)── 카테고리: 상위-하위 계층
회원 ──(1:N)── 리뷰 : 한 회원이 여러 리뷰
상품 ──(1:N)── 리뷰 : 한 상품에 여러 리뷰
주문 ──(1:1)── 배송 : 한 주문에 하나의 배송┌──────────────┐ ┌──────────────┐
│ Category │ │ Product │
├──────────────┤ ├──────────────┤
│ *id (PK)│ │ *id (PK)│
│ name │───│─○──<│ cat_id (FK)│
│ parent_id │←──┘ │ name │
│ (FK, self) │ │ price │
└──────────────┘ │ stock │
└──────┬───────┘
│
┌──────────────────────┼──────────────────────┐
│ 1 │ 1 │
┌────┴─────────┐ ┌─────┴───────────┐ ┌─────┴──────┐
│ OrderItem │ │ Review │ │ User │
├──────────────┤ ├─────────────────┤ ├────────────┤
│ *id (PK)│ │ *id (PK) │ │ *id (PK)│
│ order_id(FK)│ │ product_id(FK) │ │ name │
│ prod_id (FK)│ │ user_id (FK) │ │ email │
│ quantity │ │ rating │ │ phone │
│ unit_price │ │ content │ │ address │
└────┬─────────┘ │ created_at │ └──────┬─────┘
│ N └─────────────────┘ │ 1
│ │
┌────┴──────────┐ │
│ Order │───────────────────────────────────┘
├───────────────┤ N
│ *id (PK)│
│ user_id (FK)│
│ order_date │
│ status │
│ total_amount │
└────┬──────────┘
│ 1
┌────┴──────────┐
│ Shipping │
├───────────────┤
│ *id (PK)│
│ order_id (FK)│
│ status │
│ tracking_no │
│ carrier │
│ shipped_at │
└───────────────┘Category 테이블의 parent_id는 자기 자신을 참조하는 자기 참조(Self-Referencing) 관계입니다. 이를 통해 계층 구조를 하나의 테이블로 표현합니다.
실습 2 — 학사 관리 시스템 ERD
1. 학생은 학번, 이름, 학과에 속한다
2. 교수는 교번, 이름, 학과에 속한다
3. 교수는 여러 과목을 개설한다
4. 학생은 여러 과목을 수강하고 성적을 받는다
5. 학과 정보를 별도로 관리한다 (학과장, 위치)┌──────────────┐ ┌──────────────┐
│ Department │ │ Professor │
├──────────────┤ ├──────────────┤
│ *id (PK)│ │ *id (PK)│
│ name │──│─────────○──<────│ dept_id (FK)│
│ head_prof │ │ name │
│ location │ └──────┬───────┘
└──────┬───────┘ │ 1
│ 1 │
│ ┌──────┴───────┐
┌────┴───────────┐ │ Course │
│ Student │ ├──────────────┤
├────────────────┤ │ *id (PK)│
│ *id (PK)│ │ prof_id (FK)│
│ dept_id (FK)│ │ name │
│ name │ │ credits │
└────────┬───────┘ └──────┬───────┘
│ N │ N
│ │
└───────┬───────────────────────┘
│
┌──────┴───────┐
│ Enrollment │ (교차 테이블)
├──────────────┤
│ *student_id │
│ *course_id │
│ grade │
│ semester │
└──────────────┘
학생 M ── N 과목 → Enrollment 교차 테이블로 해소
PK: {student_id, course_id} 또는 별도 대리키실습 3 — SNS 시스템 ERD
1. 사용자는 프로필(아이디, 닉네임, 자기소개)을 가진다
2. 사용자는 게시글을 작성한다 (텍스트, 이미지 URL)
3. 사용자는 다른 사용자를 팔로우한다 (M:N 자기참조)
4. 사용자는 게시글에 좋아요를 누를 수 있다
5. 사용자는 게시글에 댓글을 달 수 있다 ┌───────────────┐
│ User │
├───────────────┤
│ *id (PK)│
│ username │
│ nickname │
│ bio │
└───┬───┬───┬───┘
│ │ │
┌─────────────┘ │ └─────────────┐
│ 1 │ N │ N
│ │ │
┌────┴──────┐ ┌──────┴──────┐ ┌──────┴──────┐
│ Post │ │ Follow │ │ Like │
├───────────┤ ├─────────────┤ ├─────────────┤
│ *id (PK)│ │ *follower_id│ │ *user_id │
│ user_id │ │ *following_id│ │ *post_id │
│ content │ │ created_at │ │ created_at │
│ image_url│ └─────────────┘ └─────────────┘
│ created │
└────┬──────┘ Follow: 자기참조 M:N
│ 1 PK: {follower_id, following_id}
│
┌────┴──────┐
│ Comment │
├───────────┤
│ *id (PK)│
│ post_id │
│ user_id │
│ content │
│ created │
└───────────┘ERD 설계 시 흔한 실수
실수 1: M:N 관계를 그대로 두기
* 관계형 DB는 M:N 직접 구현 불가
* 반드시 교차(junction) 테이블로 분해
* 학생-과목 → 수강(학생ID, 과목ID, 성적)
실수 2: 복합 속성을 하나의 컬럼에
* 주소를 '서울시 강남구 역삼동 123' 하나로
* → 시/구/동/상세 분리 or 정규화 수준에 따라 결정
실수 3: 파생 데이터를 중복 저장
* 주문총액 = SUM(수량 * 단가) 인데 별도 저장
* → 갱신 이상 발생 가능
* → 의도적 반정규화인 경우 일관성 유지 방안 필요
실수 4: 카디널리티 오류
* 1:N을 M:N으로, 또는 반대로 설정
* → 업무 규칙 재확인 필수
* "학생은 하나의 학과만?" vs "복수 전공 허용?"
실수 5: 이력 관리 누락
* 상태 변경 이력이 필요한데 현재 값만 저장
* 주문 상태: pending → paid → shipped → delivered
* → 별도 이력 테이블 필요 여부 판단ERD 품질 점검 체크리스트
□ 1. 모든 개체에 PK가 존재하는가?
□ 2. FK가 참조하는 PK가 존재하는가?
□ 3. M:N 관계가 교차 테이블로 해소되었는가?
□ 4. 카디널리티와 참여 제약이 정확한가?
□ 5. 속성명이 명확하고 일관적인가?
(snake_case 통일 등)
□ 6. 자기참조 관계가 올바르게 표현되었는가?
□ 7. 약한 개체의 식별 관계가 표시되었는가?
□ 8. 다중값 속성이 별도 테이블로 분리되었는가?
□ 9. 모든 테이블이 최소 3NF를 만족하는가?
□ 10. 업무 규칙이 ERD에 충실히 반영되었는가?ERD에서 DDL 변환
완성된 ERD에서 SQL DDL을 도출하는 과정입니다.
-- 카테고리 (자기참조)
CREATE TABLE category (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
parent_id INT,
FOREIGN KEY (parent_id) REFERENCES category(id)
);
-- 회원
CREATE TABLE user (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
phone VARCHAR(20),
address VARCHAR(200)
);
-- 상품
CREATE TABLE product (
id INT PRIMARY KEY AUTO_INCREMENT,
category_id INT NOT NULL,
name VARCHAR(200) NOT NULL,
price DECIMAL(10,2) NOT NULL,
stock INT DEFAULT 0,
FOREIGN KEY (category_id) REFERENCES category(id)
);
-- 주문
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
order_date DATETIME DEFAULT CURRENT_TIMESTAMP,
status VARCHAR(20) DEFAULT 'pending',
total_amount DECIMAL(12,2),
FOREIGN KEY (user_id) REFERENCES user(id)
);
-- 주문상세 (교차 테이블)
CREATE TABLE order_item (
id INT PRIMARY KEY AUTO_INCREMENT,
order_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL,
unit_price DECIMAL(10,2) NOT NULL,
FOREIGN KEY (order_id) REFERENCES orders(id),
FOREIGN KEY (product_id) REFERENCES product(id)
);
-- 리뷰
CREATE TABLE review (
id INT PRIMARY KEY AUTO_INCREMENT,
product_id INT NOT NULL,
user_id INT NOT NULL,
rating TINYINT CHECK (rating BETWEEN 1 AND 5),
content TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (product_id) REFERENCES product(id),
FOREIGN KEY (user_id) REFERENCES user(id)
);ERD 표기법 종합 정리
┌──────────────────────────────────────────────────────────┐
│ ERD 표기법 핵심 정리 │
├──────────────────────────────────────────────────────────┤
│ │
│ 1. Chen 표기법 │
│ * 개체(□), 관계(◇), 속성(○) 분리 │
│ * 개념적 모델링, 학습/시험에 적합 │
│ * 속성이 많으면 복잡해짐 │
│ │
│ 2. Crow's Foot (IE) 표기법 │
│ * 속성을 박스 안에, 관계를 선의 끝 기호로 │
│ * 실무 표준, 논리적/물리적 모델링에 적합 │
│ * 식별(실선)/비식별(점선) 관계 구분 │
│ │
│ 3. UML 클래스 다이어그램 │
│ * 3단 박스(클래스명/속성/메서드) │
│ * 객체지향 설계와 통합할 때 유용 │
│ * 카디널리티를 숫자 범위로 명시 │
│ │
│ 4. ERD 설계 순서 │
│ 요구사항 → 개체 식별 → 속성 정의 → 관계 분석 │
│ → 카디널리티 결정 → ERD 작성 → DDL 변환 │
│ │
│ 5. ERD 도구 선택 │
│ * 학습/팀 프로젝트: ERDCloud │
│ * 코드 기반 빠른 작성: dbdiagram.io │
│ * MySQL 연동: MySQL Workbench │
│ * 범용: draw.io │
│ │
└──────────────────────────────────────────────────────────┘다음 절에서는 이 ER 모델을 실제 릴레이션(테이블)으로 변환하는 규칙을 다루겠습니다.