데이터 모델은 현실 세계의 정보나 데이터를 시스템으로 구축하기 위해 추상화하여 체계적으로 표현한 모형이다.
출처 : 핵심 데이터 모델링 (저자 : 유동오)

출처 : 핵심 데이터 모델링 (저자 : 유동오)
어떤 방식이든 프로젝트 관련자들과 중간 과정을 공유하고 의견을 반영하는 것이 반드시 필요하다
하향식은 많은 경험과 업무 지식이 필요하다
대부분 ER 모델을 사용한다
현실 세계에 실제로 존재하는 실체 또는 개념
* 실체 : 고객, 상품, 직원
* 개념 : 조직, 서비스, 직업
엔티티와 엔티티 간에 존재하는 업무 규칙을 정의하고, 엔티티 간에 어떤 관계가 이루어질 수 있는지 표현
Cardinality : 엔티티 인스턴스 하나가 다른 엔티티 인스턴스 몇 개와 대응되는지 표현 (최대 인스턴스 수)
1 : 1, 1 : M, M : N
Optionality : 해당 엔티티 인스턴스에 대해 상대 엔티티에 인스턴스가 반드시 존재해야 하는지 표현
Identifier Inheritence : 다른 엔티티의 식별자를 상속받을 때, 식별자로 받을지, 일반 속성으로 받을지 표현
즉, 해당 테이블에서 FK가 PK인지 아니면 일반 컬럼인지에 따라 구분한다
Relationsip Name : 관계 이름
데이터를 표현하는 가장 작은 단위
속성명 : 속성의 이름
식별자 여부 : PK 인지 아닌지
Optionality : Not Null 인지 아닌지
이외에 Conditional로 구분할 때도 있는데, Conditional은 특정 조건에 대해서 값을 가져야 할 때이다. 실제로 구현할 때는 어플리케이션 로직, 트리거, CHECK 제약 조건 등을 이용해서 구현할 수 있다
Domain : 속성이 허용하는 데이터 형식과 범위. 즉, 속성의 자료형과 제약 조건(값의 범위)을 말한다
엔티티에서 인스턴스를 개별적으로 식별할 수 있는 속성
가능하면 본질 식별자를 사용하는 것이 좋지만, 인조 식별자를 사용하는 경우가 더 많다
관계형 데이터 모델 : 데이터를 2차원 테이블 형식으로 정의하고 표현한 모델
Relation : 데이터를 표현한 2차원 테이블. 릴레이션 스키마(테이블 헤더)와 릴레이션 인스턴스(tuple)로 구성된다
릴레이션 스키마는 릴레이션명과 어트리뷰트로 구성된다
어트리뷰트는 더 쪼갤 수 없는 원자 값으로 구성된다
튜플은 모두 다른 값을 가지며 중복된 튜플을 허용하지 않는다. 또한, 순서와 무관하다 (Set)
함수 종속성 : 어떤 릴레이션 R에서 속성 X의 값 각각에 대해 속성 Y의 값이 오직 하나만 연관되어 있을 때 Y는 X에 대해 함수적으로 종속되어 있다고 한다 (X→Y)
예시 : 고객번호 → (고객명, 생년월일, 전화번호, 주소)
Full Functional Dependency : X에 대해 Y가 함수적으로 종속되어 있지만, X의 부분 집합에 대해서는 종속되지 않은 경우
예시 : (주문번호, 상품코드) → (주문수량) 일 때, (주문번호) → (주문수량) 또는 (상품코드) → (주문수량) 은 아닌 경우
Partial Functional Dependency : 완전 함수종속이 아닌 경우
예시 : (주문번호, 상품코드) → (상품단가) 일 때, 상품코드 → 상품단가 는 종속되어 있다
Transitive Functional Dependency : X → Y, Y → Z 일 때, X → Z 가 성립한다. 이 때 속성 Z는 X에 대해 이행적 함수종속성을 갖는다고 한다
예시 : (주문번호) → (고객번호), (고객번호) → (고객명) 이면 (주문번호) → (고객명) 이다
정규화 : 이상(Anomaly) 현상을 최소화하기 위해 좀 더 작은 단위의 테이블로 설계하는 과정
모든 속성이 원자값을 가져야 한다. 즉, 중복 컬럼과 다중 값을 제거하는 것이다
예시
중복 컬럼 : 전화번호1, 전화번호2 와 같이 의미적으로 같은 컬럼 → 전화번호 테이블을 따로 만든다
다중 값 : 전화번호 컬럼 안에 두 개의 전화번호가 들어있는 경우 (010-1234-5678, 010-1111-2222) → 전화번호 테이블을 따로 만든다
하지만 전화번호도 세 부분으로 더 나눌 수 있는 것 아닌가?
원자성에 대해 이 부분이 모호할 수 있는데, 정의된 규칙은 없고 업무에 따라 선택하면 된다. 전화번호의 예로 봤을 때, 이 데이터를 사용하는 프로그램에서 항상 파싱을 해서 사용하는 경우이면 컬럼을 나눠서 저장하는 것이 좋고 아니면 하나의 컬럼으로 저장하는 것이 좋다
제1정규형을 만족하면서 부분 함수종속을 제거한 것
기본키가 복합키인 경우에만 해당된다
제2정규형을 만족하면서 이행적 함수종속을 제거한 것. 즉, PK에 의해서만 다른 컬럼들 값이 결정되어야 한다
→ 사실, BCNF에는 맞는 말이지만 3NF에는 완전히 들어맞진 않는다
제3정규형을 만족하면서 모든 결정자가 후보키인 것. 즉, 다른 컬럼들 값을 결정하는 결정자는 유일성과 최소성을 만족해야한다
→ PK는 유일성과 최소성을 만족해야한다
| 조건 | 3NF 만족? | BCNF 만족? |
|---|---|---|
| 결정자가 기본키(PK) | ✅ | ✅ |
| 결정자가 후보키 (PK 아님) | ✅ | ✅ |
| 결정자가 후보키도 아님 | ✅ (조건부) | ❌ |
* 조건부 : 종속되는 속성 B가 후보키의 일부일 때만
* 후보키의 일부 : 후보키가 복합키일 때 그 속성 중 하나인 경우
Multi-valued Dependency 제거
Multi-valued Dependency : 하나의 키에 대해 서로 독립적인 여러 값이 종속될 경우
예시
(직원명, 기술, 프로젝트) 컬럼이 있을 때, 기술과 프로젝트는 관련이 없지만 데이터가 반복해서 들어가는 상황
| 직원명 | 기술 | 프로젝트 |
|---|---|---|
| 철수 | Java | 프로젝트A |
| 철수 | Python | 프로젝트A |
| 철수 | Java | 프로젝트B |
| 철수 | Python | 프로젝트B |
Join Dependency 제거
Join Dependency : 비손실 조인이 불가능한 구조
테이블을 여러 개로 분해한 후 다시 조인했을 때 원래 데이터가 정확히 복원되어야 하며,
조인을 해야만 알 수 있는 의미 없는 중복 정보는 제거해야 한다
예시
아래 테이블을 (프로젝트-공급자), (프로젝트-부품), (공급자-부품) 의 세 테이블로 쪼개지 말고 함께 써야한다
| 프로젝트 | 공급자 | 부품 |
|---|---|---|
| P1 | S1 | A |
| P1 | S1 | B |
| P1 | S2 | A |