DB 설계 과정
1
2
3
4
5
6
7
8
9
10
11
| 요구사항 분석
↓
개념적 설계 (ER 모델)
↓
논리적 설계 (릴레이션 변환)
↓
정규화
↓
물리적 설계 (인덱스, 저장 구조)
↓
구현
|
ER 모델 (Entity-Relationship Model)
현실 세계를 개체(Entity)와 관계(Relationship)로 모델링하는 개념적 데이터 모델.
구성 요소
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| 1. 개체 (Entity)
- 독립적으로 존재하는 현실 세계의 객체
- 직사각형으로 표현
- 예: 학생, 과목, 교수
2. 속성 (Attribute)
- 개체의 특성
- 타원으로 표현
├── 단순 속성: 더 이상 분해 불가 (이름)
├── 복합 속성: 분해 가능 (주소 → 시, 구, 동)
├── 단일값 속성: 하나의 값 (학번)
├── 다치 속성: 여러 값 (전화번호) - 이중 타원
├── 저장 속성: 실제 저장 (생년월일)
└── 유도 속성: 계산으로 도출 (나이) - 점선 타원
3. 관계 (Relationship)
- 개체 간의 연관성
- 마름모로 표현
- 예: 학생 --수강-- 과목
4. 키 속성
- 개체를 유일하게 식별
- 밑줄로 표현
|
관계의 카디널리티 (대응 수)
1
2
3
4
5
6
7
8
9
10
11
12
13
| 1. 1:1 (일대일)
- 하나의 개체가 상대 개체 하나와만 연관
- 예: 학생 ── 졸업논문 (한 학생이 하나의 논문)
2. 1:N (일대다)
- 하나의 개체가 상대 여러 개체와 연관
- 예: 학과 ── 학생 (하나의 학과에 여러 학생)
- 가장 흔한 유형
3. N:M (다대다)
- 양쪽 모두 여러 개체와 연관
- 예: 학생 ── 과목 (학생은 여러 과목, 과목에 여러 학생)
- 릴레이션 변환 시 별도 테이블 생성 필요
|
참여 제약 조건
1
2
3
4
5
6
7
8
9
| 전체 참여 (Total Participation)
- 모든 개체가 관계에 참여해야 함
- 이중 실선으로 표현
- 예: 모든 학생은 반드시 학과에 소속
부분 참여 (Partial Participation)
- 일부 개체만 관계에 참여
- 단일 실선으로 표현
- 예: 일부 교수만 프로젝트에 참여
|
약한 개체 (Weak Entity)
1
2
3
4
5
6
7
| - 자체 키 속성이 없어 독립적으로 존재할 수 없는 개체
- 소유 개체(Owner Entity)에 종속
- 이중 직사각형으로 표현
- 부분키(Partial Key): 소유 개체의 키와 결합하여 유일하게 식별
예: 직원(소유) ──── 부양가족(약한)
직원번호 + 부양가족이름 = 유일 식별
|
ER 모델 → 릴레이션 변환
변환 규칙
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| 1. 강한 개체 → 릴레이션
- 개체의 속성이 릴레이션의 속성
- 키 속성이 기본키
Student(id, name, dept)
2. 약한 개체 → 릴레이션
- 소유 개체의 기본키를 FK로 포함
- 부분키 + FK = 기본키
Dependent(emp_id, dep_name, relation)
PK: (emp_id, dep_name), FK: emp_id → Employee
3. 1:1 관계 → 한쪽에 FK 추가
- 전체 참여 쪽에 FK를 넣는 것이 유리 (NULL 방지)
Student(id, name, thesis_id) -- FK 추가
4. 1:N 관계 → N쪽에 FK 추가
- N쪽 릴레이션에 1쪽의 PK를 FK로 추가
Student(id, name, dept_id) -- FK: dept_id → Department
5. N:M 관계 → 별도 릴레이션 생성
- 양쪽의 PK를 FK로 포함하고 이들이 PK
- 관계의 속성도 포함
Enrollment(student_id, course_id, grade)
PK: (student_id, course_id)
6. 다치 속성 → 별도 릴레이션
- 개체의 PK + 다치 속성으로 구성
StudentPhone(student_id, phone)
PK: (student_id, phone)
|
변환 예시
1
2
3
4
5
6
7
8
9
10
11
12
| ER 모델:
[학생] ──(수강)── [과목]
학번 성적 과목번호
이름 과목명
학과 학점
릴레이션 변환:
Student(student_id, name, dept)
Course(course_id, course_name, credit)
Enrollment(student_id, course_id, grade)
FK: student_id → Student
FK: course_id → Course
|
정규화 (Normalization)
릴레이션을 분해하여 이상(Anomaly)을 제거하는 과정.
이상 (Anomaly)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| 잘못 설계된 릴레이션:
StudentCourse(학번, 이름, 학과, 과목번호, 성적)
1. 삽입 이상 (Insertion Anomaly)
- 수강 기록 없이 학생 정보만 삽입 불가
- 과목번호가 PK의 일부이므로 NULL 불가
2. 삭제 이상 (Deletion Anomaly)
- 수강 기록 삭제 시 학생 정보도 함께 삭제
- 마지막 수강 과목을 삭제하면 학생 자체가 사라짐
3. 갱신 이상 (Update Anomaly)
- 학과 변경 시 해당 학생의 모든 튜플을 수정해야 함
- 일부만 수정하면 불일치 발생
|
정규형의 관계
1
2
3
4
5
6
7
8
9
| 비정규형 → 1NF → 2NF → 3NF → BCNF → 4NF → 5NF
높은 정규형일수록:
✅ 이상(Anomaly) 감소
✅ 데이터 중복 감소
❌ 조인 연산 증가 (릴레이션 분해)
❌ 질의 성능 저하 가능
실무에서는 보통 3NF 또는 BCNF까지 정규화
|
제1정규형 (1NF)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| 조건: 모든 속성 값이 원자값(Atomic Value)이어야 함
→ 다치 속성, 복합 속성, 반복 그룹 제거
위반 예시:
┌──────┬────────┬─────────────────┐
│ 학번 │ 이름 │ 전화번호 │
├──────┼────────┼─────────────────┤
│ 1001 │ 홍길동 │ 010-1234, 02-555│ ← 다치 값!
└──────┴────────┴─────────────────┘
1NF 변환:
┌──────┬────────┬──────────┐
│ 학번 │ 이름 │ 전화번호 │
├──────┼────────┼──────────┤
│ 1001 │ 홍길동 │ 010-1234 │
│ 1001 │ 홍길동 │ 02-555 │
└──────┴────────┴──────────┘
또는 별도 테이블로 분리 (추천):
Student(학번, 이름)
StudentPhone(학번, 전화번호)
|
제2정규형 (2NF)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| 조건: 1NF + 기본키에 대한 부분 함수적 종속 제거
→ 기본키가 복합키일 때 의미 있음 (단일 키이면 자동으로 2NF)
위반 예시:
Enrollment(학번, 과목번호, 이름, 학과, 성적)
PK: {학번, 과목번호}
FD:
{학번, 과목번호} → 성적 (완전 종속 ✅)
{학번} → 이름, 학과 (부분 종속 ❌)
2NF 변환:
Student(학번, 이름, 학과) -- 부분 종속 분리
Enrollment(학번, 과목번호, 성적) -- 완전 종속만 유지
|
제3정규형 (3NF)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| 조건: 2NF + 이행적 함수적 종속 제거
→ 비키 속성이 기본키에 직접 종속해야 함
위반 예시:
Student(학번, 이름, 학과, 학과장)
PK: {학번}
FD:
학번 → 학과 (직접 종속 ✅)
학과 → 학과장 (비키 → 비키)
학번 → 학과장 (이행 종속 ❌)
3NF 변환:
Student(학번, 이름, 학과) -- FK: 학과 → Department
Department(학과, 학과장) -- 이행 종속 분리
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| 조건: 모든 결정자가 후보키여야 함
→ 3NF보다 강한 조건
3NF vs BCNF:
3NF: 비키 속성이 키에 직접 종속
BCNF: 모든 결정자(→의 좌변)가 후보키
위반 예시:
Teaches(학생, 과목, 교수)
PK: {학생, 과목}
FD:
{학생, 과목} → 교수 (키 → 비키 ✅)
교수 → 과목 (비키 → 키의 일부 ❌, BCNF 위반)
교수는 결정자이지만 후보키가 아님
BCNF 변환:
TeachesProf(교수, 과목) -- 교수 → 과목
StudentProf(학생, 교수) -- 분리
주의: BCNF 분해 시 함수적 종속 보존이 안 될 수 있음
→ 3NF까지만 정규화하는 경우도 있음
|
정규형 요약
| 정규형 | 조건 | 제거 대상 |
|---|
| 1NF | 원자값 | 다치 값, 반복 그룹 |
| 2NF | 1NF + 완전 함수 종속 | 부분 함수 종속 |
| 3NF | 2NF + 이행 종속 제거 | 이행적 함수 종속 |
| BCNF | 모든 결정자가 후보키 | 후보키가 아닌 결정자 |
정규형 판별 흐름
1
2
3
4
5
6
7
8
9
| 원자값인가? ─ No → 1NF 위반
│ Yes
부분 함수 종속이 있는가? ─ Yes → 2NF 위반
│ No
이행적 종속이 있는가? ─ Yes → 3NF 위반
│ No
모든 결정자가 후보키인가? ─ No → BCNF 위반
│ Yes
BCNF ✅
|
역정규화 (Denormalization)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| 정규화된 릴레이션을 의도적으로 합치는 것
이유:
- 조인 연산 비용이 큰 경우
- 읽기 성능이 중요한 경우 (OLAP, 보고서)
- 실시간 조회가 필요한 경우
방법:
1. 테이블 합치기: 자주 조인하는 테이블을 하나로
2. 중복 속성 추가: 조인 없이 조회하기 위해
3. 계산 속성 추가: 집계 값을 미리 저장
트레이드오프:
정규화 → 이상 방지, 저장 공간 절약, 쓰기 유리
역정규화 → 조회 성능 향상, 중복 허용, 읽기 유리
|
핵심 정리
1
2
3
4
5
6
| 1. DB 설계: 요구사항 → 개념적(ER) → 논리적(릴레이션) → 물리적
2. ER 모델: 개체(□) + 관계(◇) + 속성(○)
3. 카디널리티: 1:1, 1:N, N:M → N:M은 별도 테이블
4. 이상: 삽입/삭제/갱신 이상 → 정규화로 해결
5. 정규화: 1NF(원자값) → 2NF(부분종속) → 3NF(이행종속) → BCNF
6. 역정규화: 성능을 위해 의도적 중복 허용
|
면접 포인트
자주 나오는 질문
Q1. 정규화란 무엇이고 왜 하는가?
- 릴레이션을 분해하여 이상(Anomaly)을 제거하는 과정
- 삽입/삭제/갱신 이상을 방지하고 데이터 무결성을 보장
- 데이터 중복을 최소화하여 저장 공간을 절약
Q2. 1NF, 2NF, 3NF, BCNF의 차이는?
- 1NF: 모든 속성이 원자값
- 2NF: 1NF + 부분 함수 종속 제거 (복합키일 때)
- 3NF: 2NF + 이행적 함수 종속 제거
- BCNF: 모든 결정자가 후보키 (3NF보다 강한 조건)
Q3. 역정규화는 언제 하는가?
- 조인 비용이 큰 읽기 위주 시스템에서 성능 향상 목적
- OLAP, 데이터 웨어하우스, 보고서 시스템
- 쓰기 성능 + 무결성 vs 읽기 성능의 트레이드오프
Q4. ER 모델에서 N:M 관계는 어떻게 릴레이션으로 변환하는가?
- 별도의 릴레이션(교차 테이블)을 생성
- 양쪽 개체의 PK를 FK로 포함하고, 이들의 조합이 PK
- 관계 자체의 속성(예: 성적)도 해당 릴레이션에 포함
Q5. 3NF까지만 정규화하고 BCNF로 안 가는 이유는?
- BCNF 분해 시 함수적 종속 보존이 안 될 수 있음
- 3NF는 종속 보존 분해(Dependency-Preserving Decomposition)가 항상 가능
- 실무에서 3NF로 충분한 경우가 대부분
Q6. 함수적 종속에서 완전/부분/이행 종속의 차이는?
- 완전 종속: PK 전체에 의해서만 결정 (정상)
- 부분 종속: PK의 일부에 의해 결정 → 2NF 위반
- 이행 종속: A→B→C에서 A→C가 간접적으로 성립 → 3NF 위반