[Data Modeling] 데이터 λͺ¨λΈλ§ 2일차 - μ •κ·œν™”, λ°˜μ •κ·œν™”

  • DataModeling
[Data Modeling] 데이터 λͺ¨λΈλ§ 2일차 - μ •κ·œν™”, λ°˜μ •κ·œν™”

πŸ“ μ—°κ΄€ ν¬μŠ€νŒ…

1. λ“€μ–΄κ°€λ©°

이번 κΈ€μ—μ„œλŠ” 데이터 λͺ¨λΈλ§μ—μ„œ 속성과 μ‹λ³„μžλ₯Ό μ •μ˜ν•˜λŠ” 방법을 λ³΅μŠ΅ν•˜κ³ , μ •κ·œν™”μ™€ λ°˜μ •κ·œν™”μ˜ 핡심 κ°œλ…μ„ μ •λ¦¬ν•œλ‹€. 1μΌμ°¨μ—μ„œ 엔티티와 관계λ₯Ό λ„μΆœν•˜λŠ” 흐름을 λ΄€λ‹€λ©΄, 2μΌμ°¨μ—μ„œλŠ” ν…Œμ΄λΈ” ꡬ쑰λ₯Ό 더 μ•ˆμ •μ μœΌλ‘œ λ§Œλ“œλŠ” 방법과 μ„±λŠ₯을 μœ„ν•΄ μ˜λ„μ μœΌλ‘œ ꡬ쑰λ₯Ό λ°”κΎΈλŠ” 방법을 닀룬닀.

  • μ†μ„±μ˜ μœ ν˜•
  • μŠˆνΌνƒ€μž…κ³Ό μ„œλΈŒνƒ€μž…
  • μž¬κ·€μ  관계
  • 볡합킀와 λŒ€μ²΄ν‚€
  • μ •κ·œν™”
  • λ°˜μ •κ·œν™”
  • 컬럼/ν…Œμ΄λΈ” λ°˜μ •κ·œν™” νŒ¨ν„΄

2. λͺ¨λΈλ§ 속성과 μ‹λ³„μž 볡슡

데이터 λͺ¨λΈλ§μ—μ„œ μ—”ν‹°ν‹°λ₯Ό λ„μΆœν•œ λ’€μ—λŠ” 각 μ—”ν‹°ν‹°κ°€ κ°€μ Έμ•Ό ν•  속성과 μ‹λ³„μžλ₯Ό μ •μ˜ν•΄μ•Ό ν•œλ‹€. 속성은 μ—”ν‹°ν‹°λ₯Ό μ„€λͺ…ν•˜λŠ” μ„ΈλΆ€ 데이터이고, μ‹λ³„μžλŠ” μ—”ν‹°ν‹°μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό μœ μΌν•˜κ²Œ κ΅¬λΆ„ν•˜λŠ” 기쀀이닀.

2.1 Attribute

속성은 크게 기초 속성, μΆ”μΆœ 속성, 섀계 μ†μ„±μœΌλ‘œ λ‚˜λˆŒ 수 μžˆλ‹€.

μœ ν˜• 의미 μ˜ˆμ‹œ
기초 속성 μ—”ν‹°ν‹°κ°€ μ—…λ¬΄μ μœΌλ‘œ μ›λž˜ κ°€μ§€κ³  μžˆλŠ” 속성 이름, 생년월일, μ£Όμ†Œ
μΆ”μΆœ 속성 기초 μ†μ„±μœΌλ‘œλΆ€ν„° 계산, 집계, κ°€κ³΅ν•΄μ„œ 얻을 수 μžˆλŠ” 속성 μ΄κΈˆμ•‘, ν‰κ· μ μˆ˜, λˆ„μ κΈˆμ•‘
섀계 속성 μ‹€μ œ μ—…λ¬΄μ—λŠ” μ—†μ§€λ§Œ μ‹œμŠ€ν…œ νš¨μœ¨μ„ μœ„ν•΄ μ„€κ³„μžκ°€ λΆ€μ—¬ν•˜λŠ” 속성 순번, μ½”λ“œ, μƒνƒœκ°’

μΆ”μΆœ 속성과 섀계 속성은 νŽΈλ¦¬ν•˜μ§€λ§Œ 데이터 쀑볡과 무결성 문제λ₯Ό λ§Œλ“€ 수 μžˆλ‹€. λ”°λΌμ„œ λ‹¨μˆœνžˆ μ‘°νšŒκ°€ νŽΈν•˜λ‹€λŠ” 이유만으둜 μΆ”κ°€ν•˜κΈ°λ³΄λ‹€λŠ”, 정합성을 μœ μ§€ν•  λ°©λ²•κΉŒμ§€ ν•¨κ»˜ 섀계해야 ν•œλ‹€.

2.2 데이터 λͺ¨λΈλ§ κ³Όμ •

데이터 λͺ¨λΈλ§μ€ 보톡 λ‹€μŒ νλ¦„μœΌλ‘œ μ§„ν–‰λœλ‹€.

  1. 업무 μš”κ΅¬μ‚¬ν•­ 뢄석
  2. 핡심 μ—”ν‹°ν‹° λ„μΆœ
  3. μ—”ν‹°ν‹° κ°„ 관계 μ •μ˜
  4. 속성 μ •μ˜
  5. μ‹λ³„μž μ •μ˜
  6. μ •κ·œν™” μˆ˜ν–‰
  7. 물리 λͺ¨λΈ λ³€ν™˜
  8. μ„±λŠ₯ μš”κ΅¬μ‚¬ν•­μ— λ”°λ₯Έ λ°˜μ •κ·œν™” κ²€ν† 

3. μŠˆνΌνƒ€μž…κ³Ό μ„œλΈŒνƒ€μž…

μŠˆνΌνƒ€μž…κ³Ό μ„œλΈŒνƒ€μž…μ€ 곡톡 속성과 κ°œλ³„ 속성을 λΆ„λ¦¬ν•΄μ„œ ν‘œν˜„ν•˜λŠ” λͺ¨λΈλ§ 방식이닀. μŠˆνΌνƒ€μž…μ€ 곡톡 속성을 κ°€μ§€λŠ” μƒμœ„ 엔티티이고, μ„œλΈŒνƒ€μž…μ€ νŠΉμ • μœ ν˜•μ—λ§Œ ν•„μš”ν•œ 속성을 κ°€μ§€λŠ” ν•˜μœ„ μ—”ν‹°ν‹°λ‹€.

예λ₯Ό λ“€μ–΄ μƒν’ˆμ΄λΌλŠ” 곡톡 κ°œλ… μ•„λž˜μ— μ˜¨λΌμΈμƒν’ˆ, μ˜€ν”„λΌμΈμƒν’ˆ, B2Bμƒν’ˆ 같은 μœ ν˜•μ΄ μžˆμ„ 수 μžˆλ‹€. μ΄λ•Œ μƒν’ˆλͺ…, 가격, 재고처럼 κ³΅ν†΅μœΌλ‘œ ν•„μš”ν•œ 속성은 μƒν’ˆμ— 두고, μœ ν˜•λ³„ 속성은 각 μ„œλΈŒνƒ€μž…μ— λ‘”λ‹€.

3.1 포함 관계 μ œμ•½μ‘°κ±΄

μ„œλΈŒνƒ€μž… 관계λ₯Ό μ‹€μ œ ν…Œμ΄λΈ”μ— λ°˜μ˜ν•  λ•ŒλŠ” μ œμ•½μ‘°κ±΄μ„ 톡해 μ΅œμ†Œ ν•˜λ‚˜μ˜ μœ ν˜•μ— μ†ν•˜λ„λ‘ κ°•μ œν•  수 μžˆλ‹€.

CREATE TABLE product (
  product_id   VARCHAR(10) PRIMARY KEY,
  product_name VARCHAR(100) NOT NULL,
  price        DECIMAL(10,2),
  stock        INT DEFAULT 0,
  online_yn    CHAR(1) DEFAULT 'N',
  offline_yn   CHAR(1) DEFAULT 'N',
  b2b_yn       CHAR(1) DEFAULT 'N',
  CONSTRAINT chk_at_least_one
    CHECK (online_yn = 'Y' OR offline_yn = 'Y' OR b2b_yn = 'Y')
);

μœ„ μ œμ•½μ‘°κ±΄μ€ ν•˜λ‚˜μ˜ μƒν’ˆμ΄ 온라인, μ˜€ν”„λΌμΈ, B2B 쀑 μ΅œμ†Œ ν•˜λ‚˜μ˜ μ±„λ„μ—λŠ” λ°˜λ“œμ‹œ μ†ν•˜λ„λ‘ 보μž₯ν•œλ‹€.

4. μž¬κ·€μ  관계

μž¬κ·€μ  κ΄€κ³„λŠ” ν•˜λ‚˜μ˜ μ—”ν‹°ν‹°κ°€ 자기 μžμ‹ κ³Ό 관계λ₯Ό λ§ΊλŠ” ꡬ쑰닀. 같은 ν…Œμ΄λΈ” μ•ˆμ—μ„œ νŠΉμ • ν–‰μ˜ FKκ°€ λ‹€μ‹œ 같은 ν…Œμ΄λΈ”μ˜ PKλ₯Ό μ°Έμ‘°ν•œλ‹€.

λŒ€ν‘œμ μΈ μ˜ˆμ‹œλŠ” 직원과 직속 μƒμ‚¬μ˜ 관계닀. 직원도 같은 직원 ν…Œμ΄λΈ”μ— μ‘΄μž¬ν•˜κ³ , 직속 상사도 같은 직원 ν…Œμ΄λΈ”μ— μ‘΄μž¬ν•œλ‹€.

erDiagram
    direction LR
    EMPLOYEE ||..o{ EMPLOYEE : "감독"

    EMPLOYEE["직원"] {
        int employee_id PK "μ§μ›λ²ˆν˜Έ"
        int manager_employee_id FK "μ§μ†μƒμ‚¬μ§μ›λ²ˆν˜Έ"
        string employee_name "직원λͺ…"
        date hired_at "μž…μ‚¬μΌ"
    }

μž¬κ·€μ  관계λ₯Ό 섀계할 λ•ŒλŠ” μ΅œμƒμœ„ λ°μ΄ν„°μ˜ FKλ₯Ό NULL둜 ν—ˆμš©ν• μ§€, λ³„λ„μ˜ 루트 데이터λ₯Ό λ‘˜μ§€ 같은 κ·œμΉ™λ„ ν•¨κ»˜ μ •ν•΄μ•Ό ν•œλ‹€.

5. 볡합킀와 λŒ€μ²΄ν‚€

μ‹λ³„μžλ₯Ό 섀계할 λ•ŒλŠ” 볡합킀λ₯Ό μ‚¬μš©ν• μ§€, 순번 기반의 λŒ€μ²΄ν‚€λ₯Ό μ‚¬μš©ν• μ§€ κ²°μ •ν•΄μ•Ό ν•œλ‹€. μ‹€λ¬΄μ—μ„œλŠ” μˆœλ²ˆν‚€ + UNIQUE 볡합킀 νŒ¨ν„΄μ„ 많이 μ‚¬μš©ν•œλ‹€. μˆœλ²ˆν‚€λ‘œ μ°Έμ‘°λ₯Ό λ‹¨μˆœν•˜κ²Œ λ§Œλ“€κ³ , μ—…λ¬΄μ μœΌλ‘œ μ€‘λ³΅λ˜λ©΄ μ•ˆ λ˜λŠ” 쑰합은 UNIQUE μ œμ•½μ‘°κ±΄μœΌλ‘œ 보μž₯ν•˜λŠ” 방식이닀.

5.1 볡합킀λ₯Ό κ³ λ €ν•  λ•Œ

λ³΅ν•©ν‚€λŠ” 관계 μžμ²΄κ°€ μ‹λ³„μžκ°€ λ˜λŠ” κ²½μš°μ— μ ν•©ν•˜λ‹€. 특히 M:N 관계λ₯Ό ν•΄μ†Œν•˜κΈ° μœ„ν•œ 쀑간 ν…Œμ΄λΈ”μ—μ„œ 자주 μ‚¬μš©ν•œλ‹€.

  • 관계 μžμ²΄κ°€ 킀인 경우
  • 쀑간 ν…Œμ΄λΈ”
  • λ³€κ²½ κ°€λŠ₯성이 거의 μ—†λŠ” 경우
  • μ’‹μ•„μš”, μˆ˜κ°•μ‹ μ²­, 주문상세 같은 데이터
erDiagram
    direction LR
    MEMBER ||--o{ COURSE_ENROLLMENT : "μ‹ μ²­"
    COURSE ||--o{ COURSE_ENROLLMENT : "포함"

    MEMBER["νšŒμ›"] {
        int member_id PK "νšŒμ›λ²ˆν˜Έ"
        string member_name "νšŒμ›λͺ…"
    }

    COURSE["κ°•μ˜"] {
        int course_id PK "κ°•μ˜λ²ˆν˜Έ"
        string course_name "κ°•μ˜λͺ…"
    }

    COURSE_ENROLLMENT["μˆ˜κ°•μ‹ μ²­"] {
        int member_id PK, FK "νšŒμ›λ²ˆν˜Έ"
        int course_id PK, FK "κ°•μ˜λ²ˆν˜Έ"
        date enrolled_at "신청일"
    }

5.2 μˆœλ²ˆν‚€λ₯Ό κ³ λ €ν•  λ•Œ

μˆœλ²ˆν‚€λŠ” λŒ€λΆ€λΆ„μ˜ 일반 엔티티에 μ ν•©ν•˜λ‹€. 업무 속성이 λ°”λ€” κ°€λŠ₯성이 μžˆκ±°λ‚˜, μ™ΈλΆ€ ν…Œμ΄λΈ”μ—μ„œ 자주 μ°Έμ‘°λ˜λŠ” ν…Œμ΄λΈ”μ΄λΌλ©΄ λŒ€μ²΄ν‚€λ₯Ό λ‘λŠ” 편이 κ΄€λ¦¬ν•˜κΈ° 쉽닀.

  • λŒ€λΆ€λΆ„μ˜ 일반 ν…Œμ΄λΈ”
  • 식별 속성 λ³€κ²½ κ°€λŠ₯성이 μžˆλŠ” 경우
  • ν™•μž₯ κ°€λŠ₯성을 κ³ λ €ν•΄μ•Ό ν•˜λŠ” 경우
  • νšŒμ›, μ£Όλ¬Έ, κ²Œμ‹œνŒ, μƒν’ˆ 같은 데이터

6. μ •κ·œν™”

μ •κ·œν™”λŠ” 1972λ…„ E. F. Coddκ°€ μ œμ•ˆν•œ 이둠으둜, 데이터λ₯Ό μ²΄κ³„μ μœΌλ‘œ κ΅¬μ‘°ν™”ν•΄μ„œ 쀑볡을 쀄이고 μ΄μƒν˜„μƒμ„ μ œκ±°ν•˜κΈ° μœ„ν•œ 방법이닀. μ •κ·œν™”λŠ” 데이터 무결성을 λ†’μ΄λŠ” λ°©ν–₯의 섀계닀.

6.1 μ •κ·œν™”κ°€ ν•„μš”ν•œ 이유

μ •κ·œν™”κ°€ ν•„μš”ν•œ μ΄μœ λŠ” 크게 두 κ°€μ§€λ‹€.

  1. μ—”ν‹°ν‹°λ₯Ό κ΅¬μ„±ν•˜λŠ” 속성 κ°„ 쀑볡을 μ œκ±°ν•΄ λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό μ΅œμ ν™”ν•œλ‹€.
  2. 속성 κ°„ ν•¨μˆ˜ 쒅속성 λ•Œλ¬Έμ— λ°œμƒν•˜λŠ” μ΄μƒν˜„μƒμ„ μ œκ±°ν•œλ‹€.

μ΄μƒν˜„μƒμ€ λ‹€μŒ μ„Έ κ°€μ§€λ‘œ λ‚˜λˆŒ 수 μžˆλ‹€.

μ΄μƒν˜„μƒ 의미
μž…λ ₯ 이상 λΆˆν•„μš”ν•œ 데이터가 μžˆμ–΄μ•Όλ§Œ μ›ν•˜λŠ” 데이터λ₯Ό μž…λ ₯ν•  수 μžˆλŠ” 문제
μˆ˜μ • 이상 같은 의미의 데이터λ₯Ό μ—¬λŸ¬ κ³³μ—μ„œ λͺ¨λ‘ μˆ˜μ •ν•΄μ•Ό ν•˜λŠ” 문제
μ‚­μ œ 이상 νŠΉμ • 데이터λ₯Ό μ‚­μ œν•  λ•Œ 보쑴해야 ν•  μ •λ³΄κΉŒμ§€ ν•¨κ»˜ μ‚¬λΌμ§€λŠ” 문제

예λ₯Ό λ“€μ–΄ μ£Όλ¬Έ ν…Œμ΄λΈ”μ— μ œν’ˆ μ •λ³΄κΉŒμ§€ ν•¨κ»˜ μ €μž₯λ˜μ–΄ μžˆλ‹€λ©΄, 주문이 λ°œμƒν•΄μ•Όλ§Œ μ œν’ˆ 정보λ₯Ό 등둝할 수 μžˆλ‹€. λ˜ν•œ μ œν’ˆμ˜ 재고 μˆ˜λŸ‰μ΄ μ—¬λŸ¬ μ£Όλ¬Έ 행에 쀑볡 μ €μž₯λ˜μ–΄ μžˆλ‹€λ©΄, 재고λ₯Ό λ°”κΏ€ λ•Œ μ—¬λŸ¬ 행을 λͺ¨λ‘ μˆ˜μ •ν•΄μ•Ό ν•œλ‹€. νŠΉμ • μ œν’ˆμ˜ λ§ˆμ§€λ§‰ μ£Όλ¬Έ 내역을 μ‚­μ œν•˜λ©΄ μ œν’ˆ μ •λ³΄κΉŒμ§€ μ‚¬λΌμ§€λŠ” λ¬Έμ œλ„ 생길 수 μžˆλ‹€.

6.2 제1μ •κ·œν˜•

제1μ •κ·œν˜•μ€ λͺ¨λ“  속성이 μ›μžκ°’μ„ κ°€μ Έμ•Ό ν•œλ‹€λŠ” κ·œμΉ™μ΄λ‹€. ν•˜λ‚˜μ˜ μ»¬λŸΌμ— μ—¬λŸ¬ 값을 λ„£κ±°λ‚˜ 반볡 속성을 두면 μ•ˆ λœλ‹€.

  • λͺ¨λ“  속성은 ν•˜λ‚˜μ˜ κ°’λ§Œ κ°€μ§„λ‹€.
  • 볡수 값을 κ°€μ§€λŠ” 속성은 별도 μ—”ν‹°ν‹°λ‘œ λΆ„λ¦¬ν•œλ‹€.
  • λ°˜λ³΅λ˜λŠ” μ»¬λŸΌμ€ ν–‰μœΌλ‘œ μ „ν™˜ν•œλ‹€.

6.3 제2μ •κ·œν˜•

제2μ •κ·œν˜•μ€ κΈ°λ³Έν‚€ 전체에 μ’…μ†λ˜μ§€ μ•ŠλŠ” 속성을 λΆ„λ¦¬ν•˜λŠ” 단계닀. 특히 볡합킀λ₯Ό μ‚¬μš©ν•˜λŠ” ν…Œμ΄λΈ”μ—μ„œ λΆ€λΆ„ 쒅속이 λ°œμƒν•  수 μžˆλ‹€.

예λ₯Ό λ“€μ–΄ 주문번호 + μ œν’ˆλ²ˆν˜Έκ°€ PK인 주문상세 ν…Œμ΄λΈ”μ— μ œν’ˆλͺ…이 λ“€μ–΄ μžˆλ‹€λ©΄, μ œν’ˆλͺ…은 전체 ν‚€κ°€ μ•„λ‹ˆλΌ μ œν’ˆλ²ˆν˜Έμ—λ§Œ μ’…μ†λœλ‹€. 이 경우 μ œν’ˆλͺ…은 μ œν’ˆ ν…Œμ΄λΈ”λ‘œ 뢄리해야 ν•œλ‹€.

6.4 제3μ •κ·œν˜•

제3μ •κ·œν˜•μ€ 일반 속성에 μ’…μ†λ˜λŠ” 속성을 λΆ„λ¦¬ν•˜λŠ” 단계닀. 즉, κΈ°λ³Έν‚€κ°€ μ•„λ‹Œ 속성에 λ‹€λ₯Έ 속성이 μ’…μ†λ˜λŠ” 이행 쒅속을 μ œκ±°ν•œλ‹€.

ν˜„μ—…μ—μ„œλŠ” 보톡 제3μ •κ·œν˜•κΉŒμ§€ μ§„ν–‰ν•œ λ’€, μ„±λŠ₯ μš”κ΅¬μ‚¬ν•­μ— 따라 λ°˜μ •κ·œν™”λ₯Ό κ²€ν† ν•˜λŠ” κ²½μš°κ°€ λ§Žλ‹€.

6.5 BCNF

BCNFλŠ” κ²°μ •μžκ°€ 후보킀가 μ•„λ‹Œ 경우λ₯Ό μ œκ±°ν•˜λŠ” 더 κ°•ν•œ μ •κ·œν™” ν˜•νƒœλ‹€. λ‹€μˆ˜μ˜ μ£Όμ‹λ³„μžκ°€ λ³΅μž‘ν•˜κ²Œ μ–½νžŒ 경우 μΆ”κ°€λ‘œ κ²€ν† ν•  수 μžˆλ‹€.

7. λ°˜μ •κ·œν™”

λ°˜μ •κ·œν™”λŠ” 쑰회 μ„±λŠ₯을 λ†’μ΄κ±°λ‚˜ 운영 νŽΈμ˜μ„±μ„ ν™•λ³΄ν•˜κΈ° μœ„ν•΄ μ •κ·œν™”λœ ꡬ쑰λ₯Ό μ˜λ„μ μœΌλ‘œ 일뢀 μ€‘λ³΅μ‹œν‚€λŠ” 섀계닀. μ •κ·œν™”κ°€ 무결성을 μš°μ„ ν•œλ‹€λ©΄, λ°˜μ •κ·œν™”λŠ” μ„±λŠ₯κ³Ό μ‚¬μš©μ„±μ„ μœ„ν•΄ 무결성 관리 λΉ„μš©μ„ κ°μˆ˜ν•˜λŠ” 선택이닀.

λ°˜μ •κ·œν™”λ₯Ό μ μš©ν•  λ•ŒλŠ” λ°˜λ“œμ‹œ λ‹€μŒ μ§ˆλ¬Έμ„ ν•΄μ•Ό ν•œλ‹€.

  • μ–΄λ–€ 쑰회 μ„±λŠ₯ λ¬Έμ œκ°€ μžˆλŠ”κ°€?
  • 쑰인을 μ€„μ΄λŠ” 것 외에 인덱슀둜 ν•΄κ²°ν•  수 μžˆλŠ”κ°€?
  • 쀑볡 λ°μ΄ν„°μ˜ 정합성은 μ–΄λ–»κ²Œ 보μž₯ν•  것인가?
  • Trigger, 계산 컬럼, 배치, μ• ν”Œλ¦¬μΌ€μ΄μ…˜ 둜직 쀑 μ–΄λ–€ λ°©μ‹μœΌλ‘œ 동기화할 것인가?

8. 컬럼 λ°˜μ •κ·œν™”

컬럼 λ°˜μ •κ·œν™”λŠ” ν…Œμ΄λΈ”μ€ μœ μ§€ν•˜λ˜, 쑰회 μ„±λŠ₯μ΄λ‚˜ 볡ꡬ νŽΈμ˜μ„±μ„ μœ„ν•΄ μ»¬λŸΌμ„ μΆ”κ°€ν•˜λŠ” 방식이닀.

λŒ€ν‘œμ μΈ μœ ν˜•μ€ λ‹€μŒκ³Ό κ°™λ‹€.

  1. 쀑볡 컬럼 μΆ”κ°€
  2. νŒŒμƒ 컬럼 μΆ”κ°€
  3. 이λ ₯ 컬럼 μΆ”κ°€
  4. PK 컬럼 뢄리
  5. 데이터 볡ꡬλ₯Ό μœ„ν•œ 컬럼 μΆ”κ°€

8.1 쀑볡 컬럼 μΆ”κ°€

지점λͺ…은 업무지점 ν…Œμ΄λΈ”μ— μ‘΄μž¬ν•˜μ§€λ§Œ, 사원정보λ₯Ό μ‘°νšŒν•  λ•Œλ§ˆλ‹€ 지점λͺ…κΉŒμ§€ 자주 ν•„μš”ν•˜λ‹€λ©΄ 사원정보에 지점λͺ…을 쀑볡 μ €μž₯ν•˜λŠ” 방식을 κ²€ν† ν•  수 μžˆλ‹€.

μ •κ·œν™”λœ κ΅¬μ‘°λŠ” λ‹€μŒκ³Ό κ°™λ‹€.

erDiagram
    direction LR
    BRANCH ||..o{ EMPLOYEE_INFO : "μ†Œμ†"

    BRANCH["업무지점"] {
        int branch_id PK "μ§€μ λ²ˆν˜Έ"
        string branch_name "지점λͺ…"
        string location "μ§€μ μœ„μΉ˜"
        string phone_number "μ „ν™”λ²ˆν˜Έ"
    }

    EMPLOYEE_INFO["사원정보"] {
        int employee_id PK "μ‚¬μ›λ²ˆν˜Έ"
        string employee_name "이름"
        string phone_number "μ—°λ½μ²˜"
        int branch_id FK "μ§€μ λ²ˆν˜Έ"
    }

λ°˜μ •κ·œν™”λ₯Ό μ μš©ν•˜λ©΄ 사원정보에 지점λͺ…을 쀑볡 μ €μž₯ν•œλ‹€.

erDiagram
    direction LR
    BRANCH ||..o{ EMPLOYEE_INFO : "μ†Œμ†"

    BRANCH["업무지점"] {
        int branch_id PK "μ§€μ λ²ˆν˜Έ"
        string branch_name "지점λͺ…"
        string location "μ§€μ μœ„μΉ˜"
        string phone_number "μ „ν™”λ²ˆν˜Έ"
    }

    EMPLOYEE_INFO["사원정보"] {
        int employee_id PK "μ‚¬μ›λ²ˆν˜Έ"
        string employee_name "이름"
        string phone_number "μ—°λ½μ²˜"
        int branch_id FK "μ§€μ λ²ˆν˜Έ"
        string branch_name "지점λͺ…"
    }

μ΄λ ‡κ²Œ ν•˜λ©΄ 쑰회 μ‹œ 쑰인을 쀄일 수 μžˆμ§€λ§Œ, μ—…λ¬΄μ§€μ μ˜ 지점λͺ…이 변경될 λ•Œ μ‚¬μ›μ •λ³΄μ˜ 지점λͺ…도 ν•¨κ»˜ κ°±μ‹ ν•΄μ•Ό ν•œλ‹€.

8.2 νŒŒμƒ 컬럼 μΆ”κ°€

μ£Όλ¬Έ μ΄κΈˆμ•‘μ€ μ£Όλ¬Έμƒμ„Έμ˜ μˆ˜λŸ‰κ³Ό μ œν’ˆ 단가λ₯Ό 톡해 계산할 수 μžˆλ‹€. μ›μΉ™μ μœΌλ‘œλŠ” 쑰회 μ‹œ 계산할 수 μžˆμ§€λ§Œ, λŒ€λΆ€λΆ„μ˜ μ‘°νšŒμ—μ„œ μ΄κΈˆμ•‘μ΄ ν•„μš”ν•˜κ³  계산 λΉ„μš©μ΄ 크닀면 μ£Όλ¬Έ ν…Œμ΄λΈ”μ— μ΄κΈˆμ•‘μ„ μ €μž₯ν•  수 μžˆλ‹€.

μ •κ·œν™”λœ κ΅¬μ‘°λŠ” λ‹€μŒκ³Ό κ°™λ‹€.

erDiagram
    direction LR
    ORD ||--o{ ORDER_PRODUCT : "포함"
    PRODUCT ||--o{ ORDER_PRODUCT : "주문됨"

    ORD["μ£Όλ¬Έ"] {
        int order_id PK "주문번호"
        date ordered_at "μ£Όλ¬Έλ‚ μ§œ"
    }

    ORDER_PRODUCT["μ£Όλ¬Έμ œν’ˆμƒμ„Έ"] {
        int order_id PK, FK "주문번호"
        int product_id PK, FK "μ œν’ˆλ²ˆν˜Έ"
        int quantity "μˆ˜λŸ‰"
    }

    PRODUCT["μ œν’ˆ"] {
        int product_id PK "μ œν’ˆλ²ˆν˜Έ"
        string product_name "μ œν’ˆμ΄λ¦„"
        int unit_price "단가"
    }

λ°˜μ •κ·œν™”λ₯Ό μ μš©ν•˜λ©΄ μ£Όλ¬Έ ν…Œμ΄λΈ”μ— μ΄κΈˆμ•‘ μ»¬λŸΌμ„ μΆ”κ°€ν•œλ‹€.

erDiagram
    direction LR
    ORD ||--o{ ORDER_PRODUCT : "포함"
    PRODUCT ||--o{ ORDER_PRODUCT : "주문됨"

    ORD["μ£Όλ¬Έ"] {
        int order_id PK "주문번호"
        date ordered_at "μ£Όλ¬Έλ‚ μ§œ"
        int total_amount "μ΄κΈˆμ•‘"
    }

    ORDER_PRODUCT["μ£Όλ¬Έμ œν’ˆμƒμ„Έ"] {
        int order_id PK, FK "주문번호"
        int product_id PK, FK "μ œν’ˆλ²ˆν˜Έ"
        int quantity "μˆ˜λŸ‰"
    }

    PRODUCT["μ œν’ˆ"] {
        int product_id PK "μ œν’ˆλ²ˆν˜Έ"
        string product_name "μ œν’ˆμ΄λ¦„"
        int unit_price "단가"
    }

νŒŒμƒ μ»¬λŸΌμ„ μ €μž₯ν•  λ•ŒλŠ” κ³„μ‚°λœ μ»¬λŸΌμ„ μ‚¬μš©ν•΄ 정합성을 확보할 수 μžˆλ‹€.

ALTER TABLE emp ADD (totalsum NUMBER)
GENERATED ALWAYS AS (sal + NVL(comm, 0));

8.3 λˆ„μ ν•© 컬럼 주의

곡사비 λˆ„μ μ²˜λŸΌ ν–‰ λ‹¨μœ„λ‘œ λˆ„μ ν•©μ„ μ €μž₯ν•˜λŠ” 방식은 RDB μ„€κ³„μ—μ„œλŠ” ν”Όν•˜λŠ” 것이 μ’‹λ‹€. νŠΉμ • 쀑간 ν–‰μ˜ 곡사비가 λ³€κ²½λ˜λ©΄ 이후 λͺ¨λ“  λˆ„μ κ°’μ„ λ‹€μ‹œ 계산해야 ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.

erDiagram
    direction LR
    CONSTRUCTION_WORK["곡사내역"] {
        int work_id PK "κ³΅μ‚¬λ²ˆν˜Έ"
        date worked_at "κ³΅μ‚¬μΌμž"
        int cost "곡사비"
        int accumulated_cost "κ³΅μ‚¬λΉ„λˆ„μ "
    }

λˆ„μ ν•©μ€ 쑰회 μ‹œ μœˆλ„μš° ν•¨μˆ˜λ‚˜ 집계 쿼리둜 κ³„μ‚°ν•˜λŠ” 편이 μ•ˆμ „ν•˜λ‹€.

8.4 졜근 등둝 μ—¬λΆ€ 컬럼

μ§μ›μ˜ μ°¨λŸ‰ 이λ ₯을 관리할 λ•Œ 졜근 등둝 μ°¨λŸ‰λ§Œ 자주 μ‘°νšŒν•œλ‹€λ©΄, 맀번 Top N Queryλ₯Ό μ‚¬μš©ν•˜λŠ” λŒ€μ‹  μ΅œκ·Όλ“±λ‘μ—¬λΆ€ μ»¬λŸΌμ„ λ‘˜ 수 μžˆλ‹€. μƒˆ μ°¨λŸ‰ 이λ ₯이 λ“±λ‘λ˜λ©΄ κΈ°μ‘΄ 졜근 값은 N으둜 λ°”κΎΈκ³ , μƒˆ 이λ ₯은 Y둜 μ €μž₯ν•œλ‹€.

erDiagram
    direction LR
    COMPANY_EMPLOYEE ||..o{ EMPLOYEE_CAR_HISTORY : "보유이λ ₯"

    COMPANY_EMPLOYEE["νšŒμ‚¬μ§μ›"] {
        int employee_id PK "μ§μ›λ²ˆν˜Έ"
        string employee_name "직원λͺ…"
        date hired_at "μž…μ‚¬μΌ"
    }

    EMPLOYEE_CAR_HISTORY["μ§μ›μ°¨λŸ‰μ΄λ ₯"] {
        int car_history_id PK "μ°¨λŸ‰μ΄λ ₯번호"
        int employee_id FK "μ§μ›λ²ˆν˜Έ"
        string car_number "μ°¨λŸ‰λ²ˆν˜Έ"
        string car_year "연식"
        string car_type "μ°¨μ’…"
        date registered_at "λ“±λ‘μΌμž"
        string latest_yn "μ΅œκ·Όλ“±λ‘μ—¬λΆ€"
    }

이 방식도 쑰회 μ„±λŠ₯은 μ’‹μ•„μ§€μ§€λ§Œ, μ΅œμ‹  μ—¬λΆ€λ₯Ό κ°±μ‹ ν•˜λŠ” 둜직이 λ°˜λ“œμ‹œ ν•„μš”ν•˜λ‹€.

8.5 PK 뢄리 컬럼 λ°˜μ •κ·œν™”

μ°¨λŸ‰λ²ˆν˜Έ μ•ˆμ— μ§€μ—­ 정보가 ν¬ν•¨λ˜μ–΄ μžˆλ”λΌλ„, 지역별 μ‘°νšŒκ°€ 자주 λ°œμƒν•œλ‹€λ©΄ 지역을 별도 컬럼으둜 뢄리할 수 μžˆλ‹€. μ΄λŠ” PK에 ν¬ν•¨λœ 의미λ₯Ό 쑰회 μ„±λŠ₯을 μœ„ν•΄ 컬럼으둜 λΆ„λ¦¬ν•˜λŠ” λ°˜μ •κ·œν™”λ‹€.

erDiagram
    direction LR
    CAR["μ°¨λŸ‰"] {
        string car_number PK "μ°¨λŸ‰λ²ˆν˜Έ"
        string car_type "μ°¨μ’…"
        string car_year "연식"
        string color "색상"
    }

    CAR_WITH_REGION["μ°¨λŸ‰2"] {
        string car_number PK "μ°¨λŸ‰λ²ˆν˜Έ"
        string car_type "μ°¨μ’…"
        string car_year "연식"
        string color "색상"
        string region "μ§€μ—­"
    }

8.6 데이터 볡ꡬλ₯Ό μœ„ν•œ 컬럼 μΆ”κ°€

ν˜„μž¬ μ£Όμ†Œλ§Œ μ €μž₯ν•˜λ©΄ μ£Όμ†Œ λ³€κ²½ 이λ ₯을 λ³΅κ΅¬ν•˜κΈ° μ–΄λ ΅λ‹€. 이전 값을 보관해야 ν•˜λŠ” μš”κ΅¬μ‚¬ν•­μ΄ μžˆλ‹€λ©΄ μ΄μ „μ£Όμ†Œ 같은 μ»¬λŸΌμ„ μΆ”κ°€ν•  수 μžˆλ‹€.

erDiagram
    direction LR
    CUSTOMER["고객"] {
        int customer_id PK "고객번호"
        string customer_name "고객λͺ…"
        string grade "λ“±κΈ‰"
        string address "μ£Όμ†Œ"
        string previous_address "μ΄μ „μ£Όμ†Œ"
    }

단, 이λ ₯이 μ—¬λŸ¬ 건 ν•„μš”ν•˜λ‹€λ©΄ μ΄μ „μ£Όμ†Œ 컬럼 ν•˜λ‚˜λ₯Ό μΆ”κ°€ν•˜κΈ°λ³΄λ‹€ μ£Όμ†Œ 이λ ₯ ν…Œμ΄λΈ”μ„ λ³„λ„λ‘œ λ‘λŠ” 방식이 더 μ μ ˆν•˜λ‹€.

9. ν…Œμ΄λΈ” λ°˜μ •κ·œν™”

ν…Œμ΄λΈ” λ°˜μ •κ·œν™”λŠ” 컬럼이 μ•„λ‹ˆλΌ ν…Œμ΄λΈ” ꡬ쑰 자체λ₯Ό μ‘°μ •ν•˜λŠ” 방식이닀.

λŒ€ν‘œμ μΈ 방식은 λ‹€μŒκ³Ό κ°™λ‹€.

  • 관계 병합
  • ν…Œμ΄λΈ” λΆ„ν• 
  • 쀑볡 ν…Œμ΄λΈ” μΆ”κ°€
  • 톡계 ν…Œμ΄λΈ” μΆ”κ°€
  • 이λ ₯ ν…Œμ΄λΈ” μΆ”κ°€
  • λΆ€λΆ„ ν…Œμ΄λΈ” μΆ”κ°€

9.1 μŠˆνΌνƒ€μž…κ³Ό μ„œλΈŒνƒ€μž… μœ μ§€

μŠˆνΌνƒ€μž…κ³Ό μ„œλΈŒνƒ€μž…μ„ κ·ΈλŒ€λ‘œ λΆ„λ¦¬ν•˜λ©΄ 곡톡 속성과 κ°œλ³„ 속성을 λͺ…ν™•νžˆ λ‚˜λˆŒ 수 μžˆλ‹€.

erDiagram
    direction LR
    STUDENT ||..o| UNDERGRADUATE : "ꡬ체화"
    STUDENT ||..o| GRADUATE : "ꡬ체화"

    STUDENT["학생"] {
        int student_id PK "ν•™λ²ˆ"
        string student_name "이름"
        date birth_date "생년월일"
        string phone_number "μ „ν™”λ²ˆν˜Έ"
    }

    UNDERGRADUATE["학뢀생"] {
        int student_id PK, FK "ν•™λ²ˆ"
        int grade "ν•™λ…„"
        string student_club "ν•™νšŒ"
    }

    GRADUATE["λŒ€ν•™μ›μƒ"] {
        int student_id PK, FK "ν•™λ²ˆ"
        string advisor "μ§€λ„κ΅μˆ˜"
        string research_area "연ꡬ뢄야"
    }

이 방식은 μ •κ·œν™” κ΄€μ μ—μ„œ λͺ…ν™•ν•˜μ§€λ§Œ, ν•™μƒμ˜ 전체 정보λ₯Ό μ‘°νšŒν•  λ•Œ 쑰인이 ν•„μš”ν•˜λ‹€.

9.2 1:1 One To One

μ„œλΈŒνƒ€μž…λ³„ ν…Œμ΄λΈ”μ— 곡톡 μ†μ„±κΉŒμ§€ λͺ¨λ‘ ν¬ν•¨ν•˜λŠ” 방식이닀. 학뢀생과 λŒ€ν•™μ›μƒμ„ μ™„μ „νžˆ 별도 ν…Œμ΄λΈ”λ‘œ κ΄€λ¦¬ν•œλ‹€.

erDiagram
    direction LR
    UNDERGRADUATE["학뢀생"] {
        int student_id PK "ν•™λ²ˆ"
        string student_name "이름"
        date birth_date "생년월일"
        string phone_number "μ „ν™”λ²ˆν˜Έ"
        int grade "ν•™λ…„"
        string student_club "ν•™νšŒ"
    }

    GRADUATE["λŒ€ν•™μ›μƒ"] {
        int student_id PK "ν•™λ²ˆ"
        string student_name "이름"
        date birth_date "생년월일"
        string phone_number "μ „ν™”λ²ˆν˜Έ"
        string advisor "μ§€λ„κ΅μˆ˜"
        string research_area "연ꡬ뢄야"
    }

μœ ν˜•λ³„ μ‘°νšŒλŠ” λ‹¨μˆœν•˜μ§€λ§Œ, 곡톡 속성이 μ€‘λ³΅λœλ‹€.

9.3 All In One Single Type

λͺ¨λ“  속성을 ν•˜λ‚˜μ˜ ν…Œμ΄λΈ”μ— λ„£κ³  학생 μœ ν˜•μ— 따라 ν•„μš”ν•œ 컬럼만 μ‚¬μš©ν•˜λŠ” 방식이닀.

erDiagram
    direction LR
    STUDENT["학생"] {
        int student_id PK "ν•™λ²ˆ"
        string student_type "ν•™μƒμœ ν˜•"
        string student_name "이름"
        date birth_date "생년월일"
        string phone_number "μ „ν™”λ²ˆν˜Έ"
        int grade "ν•™λ…„"
        string student_club "ν•™νšŒ"
        string advisor "μ§€λ„κ΅μˆ˜"
        string research_area "연ꡬ뢄야"
    }

쑰인이 μ—†μ–΄ μ‘°νšŒκ°€ λ‹¨μˆœν•˜μ§€λ§Œ, νŠΉμ • μœ ν˜•μ—λ§Œ ν•„μš”ν•œ μ»¬λŸΌμ€ NULL이 λ§Žμ•„μ§ˆ 수 μžˆλ‹€.

10. 정리

μ •κ·œν™”λŠ” 데이터 쀑볡과 μ΄μƒν˜„μƒμ„ 쀄이기 μœ„ν•œ κΈ°λ³Έ 원칙이닀. λ°˜μ •κ·œν™”λŠ” μ •κ·œν™” 원칙을 일뢀 깨더라도 쑰회 μ„±λŠ₯μ΄λ‚˜ 운영 νŽΈμ˜μ„±μ„ 확보해야 ν•  λ•Œ μ„ νƒν•˜λŠ” 섀계닀.

μ€‘μš”ν•œ 것은 λ°˜μ •κ·œν™”λ₯Ό μ μš©ν•  λ•Œλ§ˆλ‹€ 데이터 무결성을 μ–΄λ–»κ²Œ μœ μ§€ν•  것인지 ν•¨κ»˜ κ²°μ •ν•˜λŠ” 것이닀. 쀑볡 컬럼, νŒŒμƒ 컬럼, 졜근 μ—¬λΆ€ μ»¬λŸΌμ€ λͺ¨λ‘ μ„±λŠ₯μ—λŠ” 도움이 될 수 μžˆμ§€λ§Œ, κ°±μ‹  둜직이 μ—†μœΌλ©΄ 데이터 정합성을 깨뜨릴 수 μžˆλ‹€.

λ”°λΌμ„œ λͺ¨λΈλ§ λ‹¨κ³„μ—μ„œλŠ” μ •κ·œν™”λ₯Ό λ¨Όμ € μ μš©ν•˜κ³ , μ‹€μ œ 쑰회 νŒ¨ν„΄κ³Ό μ„±λŠ₯ μš”κ΅¬μ‚¬ν•­μ„ ν™•μΈν•œ λ’€ ν•„μš”ν•œ λΆ€λΆ„μ—λ§Œ λ°˜μ •κ·œν™”λ₯Ό μ μš©ν•˜λŠ” 것이 μ’‹λ‹€.

μ΅œμš°μ§„ ν”„λ‘œν•„

Woojin

ꡬ쑰적으둜 μ‚¬κ³ ν•˜κ³ , κ·Όκ±° 있게 κ΅¬ν˜„ν•˜κΈ° μœ„ν•΄ κΈ°λ‘ν•©λ‹ˆλ‹€.