데이터베이스(쉬운코드)

23~24. DB 정규화 : 개념, INF~BCNF, 역정규화

youbing 2025. 1. 29. 22:56
본 내용은 유튜버 쉬운코드의 강의 "데이터베이스"를 참고하여 작성하였습니다.

 

정규화(normalization) 개념

  • DB 정규화(normalization) : 데이터 중복과 insertion, update, deletion anomaly를 최소화하기 위해 일련의 normal forms(NF)에 따라 relational DB를 구성하는 과정
  • Normal forms(NF) : 정규화되기 위해 준수해야 하는 몇 가지 rule들

DB 정규화 과정

  • DB 정규화 과정 : 처음부터 순차적으로 진행하며, NF를 만족하지 못하면 만족하도록 테이블 구조를 조정한다. 앞 단계를 만족해야 다음 단계로 진행할 수 있다.
    • 1NF ~ BCNF : FD와 key만으로 정의되는 NF
    • 3NF까지 도달하면 정규화 됐다고 말하기도 함.
    • 보통 실무에서는 3NF 혹은 BCNF까지 진행 (많이 해도 4NF)
     

예제에 사용될 table 스키마 소개

  • 임직원의 월급 계좌를 관리하는 테이블
  • 월급 계좌(bank_name)는 국민은행 / 우리은행 중 하나
  • 한 임직원이 하나 이상의 월급 계좌를 등록하고 월급 비율(ratio)을 조정할 수 있음.
  • 계좌마다 등급(class)이 있음.
    • 국민 : STAR -> PRESTIGE -> LOYAL / 우리 : BRONZE -> SILVER -> GOLD
  • 한 계좌는 하나 이상의 현금 카드와 연동할 수 있음.


table의 key & prime attribute

  • super key : table에서 tuple들을 unique하게 식별할 수 있는 attributes set
  • (cardinate) key : 어느 한 attribute라도 제거하면 unique하게 tuples를 식별할 수 없는 super key
    • {account_id}, {bank_name, account_num}
  • primary key(PK) : table에서 tuple들을 unique하게 식별하려고 선택된 (candinate) key
    • {account_id}로 선택함.
  • prime attribute : 임의의 key에 속하는 attribute
    • account_id, bank_name, account_num
    • non-prime attribute : class, ratio, empl_id, empl_name, card_id

PK는 보통 밑줄로 표현


table의 functional dependency

FD 표시

  • {account_num} -> {나머지 특성들}
  • {bank_name, account_num} -> {나머지 특성들}
  • {class} -> {bank_name} : 은행마다 가지고 있는 class들이 다 달라서 class를 보면 어디 은행인지 확인할 수 있음.
  • {empl_id} -> {empl_name}

1NF 

  • 1NF : attribute의 value는 반드시 나눠질 수 없는 단일한 값이어야 한다.

전 / 후

  • 4행의 card_id가 값을 두 개 가지고 있어서 이를 행 두 개로 분리하고 card_id 외의 속성들을 복사함.
    • 1NF는 만족하지만, 중복 데이터가 생기고 primary key도 변경해야 함. -> primary key에 card_id를 추가
    • 수정된 key : {account_id, card_id}, {bank_name, account_num, card_id}

2NF

  • 2NF : 모든 non-prime attribute는 모든 key에 fully functionally dependent 해야 한다.

FD 표시

  • 모든 non-prime attribute들이 {account_id, card_id}에 partially dependent 하다.
  • 모든 non-prime attribute들이 {bank_name, account_num, card_id}에 partially dependent 하다.
    • PK에 card_id가 추가되었기 때문에 2NF를 위반한 것이므로 테이블에서 분리한다. -> 분리되기 전 테이블인 EMPLOYEE_ACCOUNT와 연결하기 위해 account_id도 추가함.
    • EMPLOYEE_ACCOUNT 테이블이 분리되면서 중복되는 4, 5번째 행을 하나만 두고 지움.

결과

  • EMPLOYEE_ACCOUNT 테이블의 key들이 fully functionally dependent 하다.
  • ACCOUNT_CARD는 PK가 {account_id, card_id}이므로 non-prime attribute가 없다.

transitive FD

  • If X -> Y & Y -> Z holds, then X -> Z is transitive FD unless either Y or Z is NOT subset of any key.

FD 표시

  • 예시 1 : {account_id} -> {empl_id} -> {empl_name}
  • 예시 2 : {bank_name, account_num} -> {empl_id} -> {empl_name}

3NF

  • 3NF : 모든 non-prime attribute는 어떤 key에도 transitively dependent 하면 안된다.
    • non-prime attribute끼리 FD가 있으면 안된다.
  • 현재는 {empl_id} -> {empl_name}가 존재함. -> 두 속성을 따로 분리함.

결과

  • 두 테이블을 연결하기 위해 EMPLOYEE_ACCOUNT 테이블에서 empl_id를 지우지 않음. (결과적으로 중복되는 데이터가 정리됨.)

 

3NF한 결과


BCNF

  • BCNF : 모든 유효한 non-trivial FD X -> Y는 X가 super key여야 한다.

  • {class} ->  {bank_name} FD가 존재함. bank_name에 불필요한 중복이 많음. -> 두 속성을 따로 분리함.
  • 두 테이블을 연결하기 위해 EMPLOYEE_ACCOUNT 테이블에서 class는 지우지 않음.

 

BCNF한 결과


2NF 참고 사항

  • 2NF는 key가 composite key가 아니라면 2NF는 자동적으로 만족한다?

-> 보통은 만족하지만, 예외가 있음.

 

전 / 후

  • {empl_id} -> {company} 할 수 있는데, {} -> {company}도 가능하므로 company 때문에 2NF를 위반한다. -> 테이블을 분리해야 함.

denormalization

  • denormalization(역정규화) : 과도한 조인(테이블을 너무 잘게 쪼개는 것)을 막기 위해 정규화 전 단계로 돌아가는 것.
  • DB를 설계할 때 과도한 조인과 중복 데이터 최소화 사이에서 적정 수준을 잘 선택할 필요가 있다.

참고 사항

  • 정규화 과정에서 4NF, 5NF, 6NF는 쓰이는 빈도에 비해 설명할 것이 많아서 생략했습니다.