개체-관계 모델 (ER Model)
ER 모델(Entity-Relationship Model)은 데이터를 개체(Entity), 속성(Attribute), 관계(Relationship)의 세 가지 요소로 표현하는 데이터 모델링 방법입니다. 1976년 피터 첸(Peter Chen)이 제안한 이 모델은 현실 세계의 복잡한 데이터 구조를 직관적으로 표현할 수 있어, 데이터베이스 설계의 사실상 표준으로 자리 잡았습니다. ER 모델의 결과물인 ERD(Entity-Relationship Diagram)는 설계자, 개발자, 기획자 모두가 소통하는 공용 언어 역할을 합니다.
개체 (Entity)
개체(Entity)는 현실 세계에서 독립적으로 존재하며, 다른 것과 구별할 수 있는 대상입니다. 사람, 장소, 사건, 개념 등 데이터베이스에서 관리해야 할 모든 것이 개체가 될 수 있습니다.
개체를 정확히 이해하려면 개체 타입(Entity Type)과 개체 인스턴스(Entity Instance)를 구분해야 합니다. 개체 타입은 같은 종류의 개체들을 묶어 정의한 것으로, 관계형 모델에서 릴레이션 스키마에 대응됩니다. 개체 인스턴스는 개체 타입에 속하는 구체적인 하나하나의 데이터로, 튜플에 대응됩니다.
개체 타입: 학생(학번, 이름, 학과)
개체 인스턴스
(2024001, 김철수, 컴퓨터공학과)
(2024002, 이영희, 전자공학과)
(2024003, 박민수, 수학과)
관계형 모델 대응
개체 타입 → 릴레이션 스키마 (테이블 구조)
개체 인스턴스 → 튜플 (행)
개체 집합 → 릴레이션 인스턴스 (테이블 데이터)개체의 종류
개체는 그 성격에 따라 여러 유형으로 분류됩니다.
강한 개체(Strong Entity)는 다른 개체에 의존하지 않고 자체적인 식별자로 독립적으로 존재하는 개체입니다. ERD에서 단일 직사각형으로 표현합니다. 학생, 직원, 상품, 부서 등이 강한 개체입니다.
약한 개체(Weak Entity)는 자신만의 식별자로는 유일하게 식별될 수 없고, 다른 개체(소유 개체, Owner Entity)에 의존하는 개체입니다. ERD에서 이중 직사각형으로 표현합니다. 약한 개체는 소유 개체의 기본키와 자신의 부분키(Partial Key, Discriminator)를 결합해야 유일하게 식별됩니다.
강한 개체 약한 개체
┌──────────┐ ╔══════════╗
│ 건 물 │ ║ 강의실 ║ (이중 직사각형으로 표기)
│ #건물코드│───소속───▶║ #호실번호║
│ 건물명 │ ║ 수용인원║
└──────────┘ ╚══════════╝
강의실의 PK = 건물코드(FK) + 호실번호(부분키)
"101호"만으로는 유일하지 않지만,
"공학관 101호"라면 유일하게 식별 가능약한 개체의 대표적인 예시를 더 살펴보겠습니다.
주문(Order) ──소유──→ 주문상세(OrderItem)
#주문번호 #순번(1,2,3...)
상품명, 수량, 가격
직원(Employee) ──소유──→ 부양가족(Dependent)
#사원번호 #이름
관계(배우자, 자녀)
서적(Book) ──소유──→ 챕터(Chapter)
#ISBN #장번호
제목약한 개체의 핵심 특성은 소유 개체가 삭제되면 함께 삭제된다는 것입니다. 주문이 삭제되면 주문상세도 의미가 없어집니다. 이것은 SQL에서 ON DELETE CASCADE로 구현됩니다.
속성 (Attribute)
속성(Attribute)은 개체의 특성이나 성질을 나타내는 것입니다. 학생의 이름, 나이, 이메일 등이 속성입니다. ER 모델에서 속성은 타원으로 표현하며, 속성의 유형에 따라 표기 방식이 달라집니다.
| 속성 유형 | 설명 | 예시 | ERD 표기 |
|---|---|---|---|
| 단순 속성 | 더 이상 분해 불가 | 이름, 나이 | 실선 타원 |
| 복합 속성 | 하위 속성으로 분해 가능 | 주소 → 시, 구, 동 | 타원 + 하위 타원 |
| 유도 속성 | 다른 속성에서 계산 | 나이 (생년월일에서 유도) | 점선 타원 |
| 다중 값 속성 | 여러 값을 가질 수 있음 | 전화번호 (여러 개) | 이중 타원 |
| 키 속성 | 개체를 유일하게 식별 | 학번, 사원번호 | 밑줄 표시 |
단순 속성과 복합 속성
단순 속성(Simple Attribute)은 더 이상 의미 있는 하위 단위로 분해할 수 없는 속성입니다. 나이, 성별, 학번 등이 단순 속성입니다.
복합 속성(Composite Attribute)은 여러 하위 속성으로 분해 가능한 속성입니다. 주소가 대표적인 복합 속성입니다. "서울시 강남구 삼성동 123번지"라는 주소를 시(서울시), 구(강남구), 동(삼성동), 상세(123번지)로 분해할 수 있습니다.
주소 (복합 속성)
├── 시 "서울시"
├── 구 "강남구"
├── 동 "삼성동"
└── 상세주소 "123번지"
이름 (복합 속성 - 국제 서비스)
├── 성 "Kim"
└── 이름 "Cheolsu"복합 속성을 분해하여 저장할지, 하나의 문자열로 저장할지는 검색과 정렬 요구사항에 따라 결정합니다. 강남구에 사는 회원을 검색해야 한다면 주소를 분해하여 저장하는 것이 유리합니다. 단순히 표시만 한다면 합쳐서 저장해도 괜찮습니다.
유도 속성
유도 속성(Derived Attribute)은 다른 속성의 값에서 계산되어 얻어지는 속성입니다. 생년월일에서 나이를 계산할 수 있으므로 나이는 유도 속성입니다. 주문 상세의 수량과 단가에서 주문 총액을 계산할 수 있으므로 총액도 유도 속성입니다.
저장하지 않는 경우 (원칙)
생년월일: 1995-03-15
나이 = YEAR(CURRENT_DATE) - YEAR(생년월일) → 매번 계산
저장하는 경우 (성능 최적화)
주문 테이블의 total_amount = SUM(수량 × 단가)
→ 수십 개 품목의 합계를 매번 계산하면 느림
→ 미리 계산하여 저장하고, 주문 변경 시 동기화유도 속성을 저장하면 조회 성능이 향상되지만, 원본 데이터와의 동기화 책임이 생깁니다. 트리거나 애플리케이션 로직에서 원본 데이터가 변경될 때 유도 속성도 함께 갱신해야 합니다.
다중 값 속성
다중 값 속성(Multi-valued Attribute)은 하나의 개체 인스턴스에 대해 여러 개의 값을 가질 수 있는 속성입니다. 한 사람이 여러 전화번호를 가질 수 있고, 한 직원이 여러 자격증을 보유할 수 있습니다.
관계형 모델에서는 1NF(제1정규형)에 의해 하나의 셀에 여러 값을 넣을 수 없습니다. 따라서 다중 값 속성은 별도의 테이블로 분리해야 합니다.
-- 잘못된 설계: 쉼표로 구분 (1NF 위반)
CREATE TABLE employees (
emp_id INT PRIMARY KEY,
name VARCHAR(50),
phones VARCHAR(200) -- "010-1234-5678, 02-555-1234" ← 나쁜 설계!
);
-- 올바른 설계: 별도 테이블로 분리
CREATE TABLE employees (
emp_id INT PRIMARY KEY,
name VARCHAR(50)
);
CREATE TABLE employee_phones (
emp_id INT,
phone VARCHAR(20),
phone_type VARCHAR(10), -- '휴대폰', '사무실', '자택'
PRIMARY KEY (emp_id, phone),
FOREIGN KEY (emp_id) REFERENCES employees(emp_id)
);키 속성
키 속성(Key Attribute)은 개체 인스턴스를 유일하게 식별하는 속성입니다. ER 다이어그램에서 속성 이름에 밑줄을 그어 표시합니다. 학생 개체의 학번, 직원 개체의 사원번호 등이 키 속성입니다.
하나의 개체가 여러 키 속성을 가질 수 있습니다. 학생의 학번과 이메일이 모두 유일하다면 둘 다 키 속성이 됩니다.
관계 (Relationship)
관계(Relationship)는 두 개 이상의 개체 사이의 연관(Association)입니다. ER 모델에서 관계는 마름모로 표현합니다. "회원이 상품을 주문한다"에서 "주문한다"가 관계입니다.
관계도 개체처럼 관계 타입(Relationship Type)과 관계 인스턴스(Relationship Instance)로 구분됩니다. 수강한다는 관계 타입이고, 김철수가 데이터베이스학을 수강한다는 관계 인스턴스입니다.
관계의 차수 (Degree)
관계에 참여하는 개체 타입의 수를 차수(Degree)라 합니다.
단항 관계 (Unary, Degree = 1)
직원 ──관리──▶ 직원 (자기 자신과의 관계)
"직원이 다른 직원을 관리한다"
이항 관계 (Binary, Degree = 2)
학생 ──수강──▶ 과목 (두 개체 간 관계)
"학생이 과목을 수강한다"
삼항 관계 (Ternary, Degree = 3)
공급자 ──공급──▶ 부품
↑
프로젝트
"공급자가 프로젝트에 부품을 공급한다"대부분의 관계는 이항 관계입니다. 삼항 이상의 관계는 가능하면 여러 이항 관계로 분해하는 것이 설계가 명확해집니다.
카디널리티 (Cardinality)
카디널리티(Cardinality)는 관계에 참여하는 개체 인스턴스의 수를 나타냅니다. 관계의 종류를 결정하는 가장 중요한 개념입니다.
1:1 관계 (one-to-one)
회원 ──────── 프로필 (1명의 회원 = 1개의 프로필)
회원 A ←──→ 프로필 A
회원 B ←──→ 프로필 B
회원 C ←──→ 프로필 C
1:N 관계 (one-to-many)
부서 ──┬───── 직원A
├───── 직원B (1부서 : N명의 직원)
└───── 직원C
영업부 ←──→ 김과장
영업부 ←──→ 이대리
개발부 ←──→ 박팀장
M:N 관계 (many-to-many)
학생A ──┬───── 과목1
학생B ──┼───── 과목2 (여러 학생 : 여러 과목)
학생C ──┘
김철수 ──→ 데이터베이스, 알고리즘
이영희 ──→ 데이터베이스, 운영체제
박민수 ──→ 알고리즘, 운영체제1:1 관계의 구현
1:1 관계는 두 개체를 하나의 테이블로 합치거나, 한쪽 테이블에 다른 쪽의 기본키를 외래키로 넣어 구현합니다.
-- 방법 1: 한쪽에 외래키 추가
CREATE TABLE members (
member_id INT PRIMARY KEY,
name VARCHAR(50)
);
CREATE TABLE profiles (
profile_id INT PRIMARY KEY,
member_id INT UNIQUE, -- UNIQUE로 1:1 보장
bio TEXT,
avatar_url VARCHAR(200),
FOREIGN KEY (member_id) REFERENCES members(member_id)
);
-- 방법 2: 하나의 테이블로 합치기
CREATE TABLE members (
member_id INT PRIMARY KEY,
name VARCHAR(50),
bio TEXT, -- 프로필 정보를 같이 저장
avatar_url VARCHAR(200)
);어떤 방법을 선택할지는 상황에 따라 다릅니다. 프로필 정보가 선택적이고(모든 회원이 프로필을 가지지 않음), 프로필 데이터가 크다면 별도 테이블이 적합합니다. 프로필이 필수이고 자주 함께 조회된다면 하나의 테이블이 적합합니다.
1:N 관계의 구현
1:N 관계는 가장 흔한 관계 유형입니다. N쪽 테이블에 1쪽의 기본키를 외래키로 추가하여 구현합니다.
CREATE TABLE departments (
dept_id INT PRIMARY KEY,
dept_name VARCHAR(50)
);
CREATE TABLE employees (
emp_id INT PRIMARY KEY,
name VARCHAR(50),
dept_id INT, -- 부서의 PK를 FK로 참조
FOREIGN KEY (dept_id) REFERENCES departments(dept_id)
);외래키는 항상 N쪽에 위치합니다. 1쪽(부서)에 외래키를 넣으면 여러 직원을 참조할 수 없기 때문입니다.
M:N 관계의 구현
M:N 관계는 관계형 데이터베이스에서 직접 표현할 수 없습니다. 중간 테이블(연결 테이블, 교차 테이블, Junction Table)을 만들어 두 개의 1:N 관계로 분해해야 합니다.
-- M:N: 학생 ←→ 과목
-- 해소: 학생 ←1:N→ 수강 ←N:1→ 과목
CREATE TABLE students (
student_id INT PRIMARY KEY,
name VARCHAR(50)
);
CREATE TABLE courses (
course_id INT PRIMARY KEY,
title VARCHAR(100)
);
-- 중간 테이블 (연결 테이블)
CREATE TABLE enrollments (
student_id INT,
course_id INT,
enrolled_at DATE DEFAULT (CURRENT_DATE),
grade CHAR(2),
PRIMARY KEY (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES students(student_id),
FOREIGN KEY (course_id) REFERENCES courses(course_id)
);중간 테이블에는 관계 자체에 속하는 속성(수강일, 성적 등)을 포함할 수 있습니다. 이러한 속성은 학생에도, 과목에도 속하지 않고, 학생과 과목의 관계에 속하는 것입니다.
참여 제약 (Participation Constraint)
관계에 개체가 참여하는 방식에 따라 전체 참여와 부분 참여로 구분합니다.
전체 참여(Total Participation)는 개체 타입의 모든 인스턴스가 관계에 반드시 참여해야 하는 것입니다. ERD에서 이중 실선으로 표현합니다. "모든 직원은 반드시 하나의 부서에 소속되어야 한다"는 직원 개체의 전체 참여입니다.
부분 참여(Partial Participation)는 개체 타입의 일부 인스턴스만 관계에 참여해도 되는 것입니다. ERD에서 단일 실선으로 표현합니다. "모든 회원이 반드시 주문을 할 필요는 없다"는 회원 개체의 부분 참여입니다.
전체 참여 (이중선)
직원 ════소속════ 부서
(모든 직원은 반드시 부서에 소속)
→ SQL: dept_id INT NOT NULL
부분 참여 (단일선)
회원 ────주문──── 상품
(주문하지 않은 회원도 존재 가능)
→ SQL: 해당 외래키에 NULL 허용참여 제약은 SQL에서 NOT NULL 제약으로 구현됩니다. 전체 참여이면 외래키 컬럼에 NOT NULL을, 부분 참여이면 NULL을 허용합니다.
관계의 속성
관계 자체가 속성을 가질 수 있습니다. 이러한 속성은 관계에 참여하는 어느 한 개체에만 속하지 않고, 두 개체의 관계에 속하는 것입니다.
학생 ──수강── 과목
수강 관계의 속성
- 수강일: 학생의 속성도, 과목의 속성도 아님
- 성적: 특정 학생이 특정 과목을 수강한 결과
학생(학번: 2024001) × 과목(코드: CS101) → 성적: A+
이 "A+"는 학생에게만 속하는 것이 아니고 (여러 과목 수강)
과목에게만 속하는 것도 아닙니다 (여러 학생 수강)ERD 표기법
ER 다이어그램의 표기법은 여러 가지가 있습니다. 각 표기법은 같은 개념을 다른 방식으로 시각화합니다.
Peter Chen 표기법
피터 첸의 원래 표기법입니다. 학술적 환경에서 주로 사용됩니다.
기호
┌────────┐ 직사각형 = 개체
│ 개 체 │
└────────┘
( 속 성 ) 타원 = 속성
◇ 관 계 ◇ 마름모 = 관계
── 선 ── 연결선
예시
┌─────┐ ┌─────┐
│학 생│═══════◇수강◇═══════│과 목│
└──┬──┘ └──┬──┘
│ │
(학번) (이름) (과목코드) (과목명)
̲학̲번̲ = 키 속성 (밑줄)IE (Information Engineering) 표기법
실무에서 가장 널리 사용되는 표기법입니다. 까마귀 발(Crow's Foot) 표기법이라고도 합니다.
──||── 정확히 하나 (mandatory one)
──|○── 0 또는 하나 (optional one)
──|<── 하나 이상 (mandatory many) ← 까마귀 발
──○<── 0 이상 (optional many) ← 까마귀 발 + 동그라미
예시: 부서 1:N 직원
┌─────────┐ ┌─────────┐
│ 부서 │──||────|<────│ 직원 │
│ dept_id │ │ emp_id │
│ name │ │ name │
└─────────┘ │ dept_id │
└─────────┘
읽는 법: "부서는 하나 이상의 직원을 가진다"
"직원은 정확히 하나의 부서에 소속된다"Barker 표기법
Oracle의 CASE Method에서 사용하는 표기법으로, ERWin 같은 도구에서 지원합니다.
┌────────────┐ ┌────────────┐
│ # dept_id │ │ # emp_id │
│ * name │←─────────────│ * name │
│ o location │ │ * dept_id │
└────────────┘ │ o salary │
└────────────┘
기호
# = 기본키 (UID)
* = 필수 (NOT NULL)
o = 선택 (NULL 허용)
실선 = 필수 참여 (NOT NULL FK)
점선 = 선택 참여 (NULL 허용 FK)표기법 비교
| 표기법 | 사용 환경 | 장점 | 단점 |
|---|---|---|---|
| Peter Chen | 학교, 학술 논문 | 직관적, 학습 용이 | 복잡한 스키마에서 번잡 |
| IE (Crow's Foot) | 실무, SI 프로젝트 | 간결, 도구 지원 풍부 | 속성 표현이 직관적이지 않음 |
| Barker | Oracle 환경 | NOT NULL 표현 명확 | Oracle 편향적 |
| UML | 객체지향 설계 통합 | 코드와 통합 용이 | DB 전문가에게 생소 |
실무에서는 IE(Crow's Foot) 표기법이 가장 널리 사용됩니다. ERWin, DA#, dbdiagram.io 등 대부분의 모델링 도구가 이 표기법을 기본으로 지원합니다.
ER 모델에서 릴레이션으로 변환
ER 모델(개념적 모델)을 관계형 모델(논리적 모델)로 변환하는 규칙을 정리합니다. 이 변환 과정은 논리적 모델링의 핵심 활동입니다.
변환 규칙
규칙 1: 강한 개체 → 릴레이션
키 속성 → 기본키
일반 속성 → 일반 컬럼
규칙 2: 약한 개체 → 릴레이션
소유 개체의 PK + 부분키 → 복합 기본키
소유 개체에 대한 FK 포함
규칙 3: 1:1 관계 → 한쪽에 FK 추가
전체 참여 쪽에 FK를 넣는 것이 유리
규칙 4: 1:N 관계 → N쪽에 FK 추가
1쪽의 PK를 N쪽에 FK로 추가
규칙 5: M:N 관계 → 새 릴레이션 생성
양쪽의 PK를 FK로 가지며, 복합 PK 구성
관계 속성은 이 릴레이션의 일반 컬럼
규칙 6: 다중 값 속성 → 별도 릴레이션
개체의 PK를 FK로 참조
규칙 7: 복합 속성 → 하위 속성을 각각 컬럼으로
또는 하나의 문자열 컬럼으로 합침변환 예시
학생(#학번, 이름, ‥주소(시, 구, 동)‥, ⊙전화번호)
│ ↑다중값
└── 수강 ── 과목(#과목코드, 과목명)
(성적, 수강일) ← 관계 속성-- 규칙 1: 강한 개체 → 릴레이션
CREATE TABLE students (
student_id INT PRIMARY KEY, -- 키 속성 → PK
name VARCHAR(50), -- 단순 속성 → 컬럼
city VARCHAR(50), -- 복합 속성 (규칙 7)
district VARCHAR(50),
dong VARCHAR(50)
);
CREATE TABLE courses (
course_id INT PRIMARY KEY,
title VARCHAR(100)
);
-- 규칙 5: M:N 관계 → 새 릴레이션
CREATE TABLE enrollments (
student_id INT,
course_id INT,
grade CHAR(2), -- 관계 속성 → 컬럼
enrolled_at DATE, -- 관계 속성 → 컬럼
PRIMARY KEY (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES students(student_id),
FOREIGN KEY (course_id) REFERENCES courses(course_id)
);
-- 규칙 6: 다중 값 속성 → 별도 릴레이션
CREATE TABLE student_phones (
student_id INT,
phone VARCHAR(20),
PRIMARY KEY (student_id, phone),
FOREIGN KEY (student_id) REFERENCES students(student_id)
);일반화와 특수화
개체 간에 상위-하위 관계(IS-A 관계)가 있을 수 있습니다.
일반화(Generalization)는 여러 하위 개체의 공통 속성을 추출하여 상위 개체를 만드는 것입니다. 정규직, 계약직, 인턴을 "직원"이라는 상위 개체로 일반화할 수 있습니다.
특수화(Specialization)는 상위 개체를 세분화하여 하위 개체를 만드는 것입니다. "직원"을 정규직, 계약직, 인턴으로 특수화할 수 있습니다.
┌──────────┐
│ 직 원 │ (상위 개체)
│ #사원번호│
│ 이름 │
│ 부서 │
└────┬─────┘
│ IS-A
┌────────┼──────────┐
┌────┴───┐ ┌──┴─────┐ ┌──┴───┐
│ 정규직 │ │계약직 │ │ 인턴 │ (하위 개체)
│ 연봉 │ │계약기간│ │멘토 │
│ 퇴직금 │ │시급 │ │학교 │
└────────┘ └────────┘ └──────┘릴레이션으로 변환하는 방법은 세 가지가 있습니다.
CREATE TABLE employees (
emp_id INT PRIMARY KEY, name VARCHAR(50), dept VARCHAR(50)
);
CREATE TABLE full_time (
emp_id INT PRIMARY KEY, salary INT, severance INT,
FOREIGN KEY (emp_id) REFERENCES employees(emp_id)
);
CREATE TABLE contract (
emp_id INT PRIMARY KEY, duration INT, hourly_rate INT,
FOREIGN KEY (emp_id) REFERENCES employees(emp_id)
);
-- 장점: 정규화됨, 제약 표현 명확
-- 단점: JOIN 필요CREATE TABLE employees (
emp_id INT PRIMARY KEY, name VARCHAR(50), dept VARCHAR(50),
emp_type VARCHAR(10), -- 'FULL', 'CONTRACT', 'INTERN'
salary INT, severance INT, -- 정규직 전용
duration INT, hourly_rate INT, -- 계약직 전용
mentor VARCHAR(50), school VARCHAR(50) -- 인턴 전용
);
-- 장점: JOIN 불필요, 단순
-- 단점: NULL 많음, 제약 표현 어려움실전 ER 모델링 예시
종합적인 ER 모델링 예시로 온라인 쇼핑몰을 설계해봅니다.
┌───────────┐ ┌─────────────┐ ┌───────────┐
│ 회원 │ │ 주문 │ │ 상품 │
│ #회원번호 │──||──|<──│ #주문번호 │──>|──||──│ #상품번호 │
│ 이름 │ │ 회원번호(FK)│ │ 상품명 │
│ 이메일 │ │ 주문일 │ ┌───│ 가격 │
│ 연락처 │ │ 총금액 │ │ │ 재고수량 │
│ 가입일 │ │ 상태 │ │ │ 카테고리 │
└───────────┘ └─────────────┘ │ └───────────┘
│ │
||─┤ ─┤
┌────┴─────┐ │
│ 주문상세 │───┘
│ 주문번호 │
│ 상품번호 │
│ 수량 │
│ 단가 │
└──────────┘
추가 관계
회원 ──1:N──→ 리뷰
상품 ──1:N──→ 리뷰
상품 ──N:1──→ 카테고리
회원 ──1:N──→ 배송지 (다중 값 속성 분리)ER 모델은 데이터베이스 설계의 청사진입니다. 잘 그려진 ERD는 수십 페이지의 문서보다 효과적으로 데이터 구조를 전달합니다. 다음 절에서는 ER 모델을 시각적으로 표현하는 ERD 표기법의 상세와 실습을 다루겠습니다.