DB ERD 관계선 정리
Posted on November 7, 2018
2026년 10월에 내용을 보강했습니다. 기호를 읽는 법, 식별/비식별 관계의 차이, 관계별 DDL, 다대다(N:N) 해소 방법을 추가했습니다.
ERD(Entity Relationship Diagram)에서 엔티티 사이를 잇는 선은 두 가지를 동시에 말해 줍니다.
- 선의 모양(실선/점선): 부모의 키가 자식에서 어떤 역할을 하는가 → 식별 / 비식별 관계
- 선 끝의 기호: 한쪽이 다른 쪽과 몇 개 대응되는가 → 관계의 종류(카디널리티)
이 글에서는 SHOP(가게)과 FOOD(음식) 두 엔티티로 정리합니다.
📌 표기법에 대해 이 글의 그림은 IE(Information Engineering, 까마귀 발) 표기법입니다. 도구나 조직마다 IDEF1X, Chen 표기법 등을 쓰기도 해서 기호 모양은 다를 수 있습니다. ERD 를 읽을 때는 먼저 어떤 표기법인지 확인하세요.
1. 선 끝의 기호 읽는 법
| 기호 | 의미 |
|---|---|
| (수직 막대) |
하나(1) |
< (까마귀 발) |
여러 개(N) |
○ (동그라미) |
0, 즉 없을 수도 있다(선택) |
기호는 이렇게 조합합니다.
| 조합 | 의미 |
|---|---|
| |
하나 |
|< |
하나 이상 (1..N) |
○| |
없거나 하나 (0..1) |
○< |
없거나 여러 개 (0..N) |
읽는 방향이 중요합니다. 선 끝의 기호는 그 기호가 붙은 쪽 엔티티가, 반대쪽 엔티티 하나당 몇 개 대응되는지를 뜻합니다.
SHOP──|<FOOD라면, 오른쪽FOOD쪽 기호가|<이므로 “가게 하나에는 음식이 하나 이상 있다” 로 읽습니다. 반대쪽SHOP끝의 기호는|(하나)이므로 “음식 하나는 반드시 하나의 가게에 속한다” 입니다.
2. 식별 관계와 비식별 관계 (실선 / 점선)
부모의 PK(기본키)가 자식 테이블에서 어떻게 쓰이는지로 나뉩니다.
| 구분 | 선 | 부모 PK 가 자식에서… |
|---|---|---|
| 식별 관계 | 실선 | 자식의 PK 의 일부가 된다 (PK 이면서 FK) |
| 비식별 관계 | 점선 | 자식의 일반 컬럼(FK) 이 된다 |
식별 관계 (실선)
자식은 부모 없이는 존재할 수 없고, 부모의 키가 자식의 식별자(PK)에 포함됩니다.
CREATE TABLE shop (
shop_id BIGINT PRIMARY KEY,
name VARCHAR(50) NOT NULL
);
-- 식별 관계: food 의 PK = (shop_id, food_no)
CREATE TABLE food (
shop_id BIGINT NOT NULL,
food_no INT NOT NULL,
name VARCHAR(50) NOT NULL,
PRIMARY KEY (shop_id, food_no),
FOREIGN KEY (shop_id) REFERENCES shop (shop_id)
);
비식별 관계 (점선)
자식은 자기만의 PK 를 갖고, 부모의 키는 일반 컬럼(FK) 으로만 참조합니다.
-- 비식별 관계: food 의 PK = food_id (부모 키는 일반 FK)
CREATE TABLE food (
food_id BIGINT PRIMARY KEY,
shop_id BIGINT NOT NULL, -- 필수 관계
name VARCHAR(50) NOT NULL,
FOREIGN KEY (shop_id) REFERENCES shop (shop_id)
);
비식별 관계는 FK 가 NOT NULL 이면 필수, NULL 을 허용하면 선택적인 관계가 됩니다. 도구에 따라 선택 관계를 점선과 다이아몬드로 따로 표시하기도 합니다.
실무에서는 어느 쪽을?
| 식별 관계 | 비식별 관계 | |
|---|---|---|
| 장점 | 자식 PK 에 부모 키가 있어 부모 기준 조회가 단순, 중복 방지가 자연스럽다 | 구조가 단순하고 변경에 유연하다 |
| 단점 | 자식 → 손자로 내려갈수록 PK 컬럼이 누적되고, 부모 키 변경의 영향이 크다 | 부모 기준으로 묶어서 유일성을 보장하려면 별도 UNIQUE 제약이 필요 |
| JPA | @IdClass / @EmbeddedId 등 복합키 매핑이 필요 |
대리키(@GeneratedValue)로 단순하게 매핑 |
그래서 실무에서는 비식별 관계와 대리키(auto increment 등)를 기본으로 쓰고, 식별 관계는 꼭 필요한 곳(예: 연결 테이블)에만 쓰는 경우가 많습니다. 반드시 이래야 하는 것은 아니고, 팀의 규칙과 데이터의 성격에 따라 정하면 됩니다.
JPA 에서의 복합키는 JPA 연관관계 매핑 - 복합키 매핑 글에서 정리했습니다.
3. 관계의 종류 (카디널리티)
(1 : 1) 관계 — 부모는 하나의 자식이 있다
- 읽기: 가게 하나에 음식 하나, 음식 하나에 가게 하나
- 구현: 한쪽에 FK 를 두고 UNIQUE 를 걸거나, 자식의 PK 를 부모의 PK 와 같게 둡니다. (식별 관계)
-- 자식 PK = 부모 PK (식별 1:1)
CREATE TABLE shop_detail (
shop_id BIGINT PRIMARY KEY,
description TEXT,
FOREIGN KEY (shop_id) REFERENCES shop (shop_id)
);
(1 : N) 관계 — 부모는 하나 이상의 자식이 있다
- 읽기: 가게 하나에 음식이 하나 이상, 음식 하나는 반드시 한 가게에 속함
- 구현: N 쪽(자식)에 FK 를 둡니다. 가장 흔한 관계입니다. (위
food테이블)
(N : N) 관계 — 하나 이상의 부모와 하나 이상의 자식이 있다
- 읽기: 가게 하나에 음식이 여러 개, 음식 하나가 여러 가게에 있을 수 있음
- 구현: 관계형 DB 는 N:N 을 직접 표현할 수 없습니다. 연결(교차) 테이블을 두어 1:N 두 개로 풀어서 구현합니다.
-- 가게와 음식이 N:N 인 경우: 연결 테이블로 해소
CREATE TABLE food (
food_id BIGINT PRIMARY KEY,
name VARCHAR(50) NOT NULL
);
CREATE TABLE shop_food (
shop_id BIGINT NOT NULL,
food_id BIGINT NOT NULL,
PRIMARY KEY (shop_id, food_id), -- 두 FK 를 합친 복합 PK (식별 관계)
FOREIGN KEY (shop_id) REFERENCES shop (shop_id),
FOREIGN KEY (food_id) REFERENCES food (food_id)
);
ERD 에서는 SHOP ─ SHOP_FOOD ─ FOOD 로, 양쪽이 모두 (1 : N) 이 됩니다. 연결 테이블에 “가격”, “등록일” 같은 속성이 필요해지는 경우가 많아서, JPA 에서도 @ManyToMany 보다 연결 엔티티를 직접 만드는 방식을 권장하는 편입니다. (JPA 연관관계 매핑 - 조인 테이블)
(1 : 1(o)) 관계 — 부모는 하나의 자식이 있을 수도 있다 (없을 수도 있다)
- 읽기: 가게에 음식이 없거나 하나
- 구현: 1:1 과 같고, 자식 쪽 레코드가 없을 수 있다는 뜻일 뿐 컬럼에 별도의 제약이 생기지는 않습니다.
(1 : N(o)) 관계 — 부모는 여러 개의 자식이 있을 수도 있다 (없을 수도 있다)
- 읽기: 가게에 음식이 없거나 여러 개
- 구현: (1 : N) 과 같습니다. 가게를 먼저 등록하고 음식을 나중에 추가하는 구조에서 흔히 씁니다.
4. 가장 많이 헷갈리는 부분: ○ 는 어느 쪽에 붙는가
○(선택) 의 위치에 따라 의미가 완전히 달라집니다.
| 모양 | 의미 | DB 에서 |
|---|---|---|
SHOP ─| ─○< FOOD |
가게는 음식이 없을 수 있다. 음식은 반드시 가게에 속한다 | food.shop_id 는 NOT NULL |
SHOP ─○| ─< FOOD |
음식은 가게 없이 존재할 수 있다 | food.shop_id 는 NULL 허용 |
- 자식 쪽 끝의
○→ “부모에게 자식이 없을 수 있다.” 별도의 DB 제약은 없습니다. - 부모 쪽 끝의
○→ “자식이 부모 없이 존재할 수 있다.” FK 가 NULL 허용이 됩니다.
위 그림 4, 5번은 자식 쪽 끝의 ○ 입니다.
5. 한눈에 정리
| 구분 | 모양 | 의미 | 구현 |
|---|---|---|---|
| 식별 관계 | 실선 | 부모 PK 가 자식 PK 의 일부 | 복합 PK (PK 이면서 FK) |
| 비식별 관계 | 점선 | 부모 PK 가 자식의 일반 컬럼 | 일반 FK (NOT NULL 이면 필수, NULL 허용이면 선택) |
| 1 : 1 | | ─ | |
서로 하나씩 | FK + UNIQUE 또는 FK = PK |
| 1 : N | | ─ |< |
부모 하나에 자식 여러 개 | N 쪽에 FK |
| N : N | |< ─ |< |
양쪽 모두 여러 개 | 연결 테이블로 1:N 두 개로 분해 |
| 1 : 1(o) | | ─ ○| |
자식이 없거나 하나 | 1:1 과 동일 |
| 1 : N(o) | | ─ ○< |
자식이 없거나 여러 개 | 1:N 과 동일 |
6. ERD 를 그릴 때 팁
- 엔티티 이름은 단수형, 관계는 동사로 읽어 보세요. “가게는 음식을 가진다” 처럼 문장으로 읽히면 관계선이 맞게 그려진 것입니다.
- 양쪽 끝을 모두 읽으세요. 한쪽만 보면 1:N 과 N:1 을 혼동하기 쉽습니다.
- N:N 이 보이면 연결 테이블이 빠진 것이 아닌지 먼저 의심하세요.
- 이 글의 그림은 draw.io 스타일입니다. ERDCloud, dbdiagram.io, MySQL Workbench 같은 도구도 많이 쓰이고, 도구마다 기본 표기법이 다를 수 있으니 설정을 확인하세요.