kimyu0218
  • [DB/쉬운코드] 정규화 (함수적 종속/1NF/2NF/3NF/BCNF)
    2024년 05월 15일 03시 23분 19초에 업로드 된 글입니다.
    작성자: @kimyu0218

    정규화

    정규화는 데이터 중복과 이상 현상을 최소화하기 위해 일련의 normal form* (NF) 에 따라 관계형 DB를 구성하는 과정이다.

    *normal form : 정규화를 위해 준수해야 하는 몇 가지 규칙

    보통 실무에서는 3NF나 BCNF까지만 진행한다

    잘못된 테이블 설계로 인한 문제

    `employee` 테이블을 다음과 같이 설계하는 상황을 가정해보자.

    emp_id, emp_name, birth_date, position, salary, dept_id, dept_name, dept_leader_id

    위 설계에 따르면 직원 정보와 부서 정보가 `employee` 테이블에서 모두 관리된다. (2개의 관심사가 하나의 테이블에 존재한다!)
     
    1번 직원과 2번 직원이 같은 부서에 속한다면 어떤 상황이 발생할까? `dept_id`, `dept_name`, `dept_leader_id`가 중복으로 저장된다. 이는 저장 공간을 낭비하고 데이터 불일치를 유발할 수 있다. 그리고 부서가 정해지지 않은 직원이나 부서원이 없는 부서를 만들어야 하는 경우 null값을 과도하게 사용하는 상황이 발생한다.

    🤔 바른 DB schema를 설계하는 방법
    • 의미적으로 관련있는 속성끼리 테이블을 구성한다. (= 관심사별로 테이블을 구성한다)
    • 중복된 데이터를 최대한 허용하지 않도록 설계한다.

     

    FD; functional dependency

    emp_id, emp_name, birth_date, position, salary

    위의 스키마에 따르면 `emp_id` 값에 따라 `emp_name, birth_date, position`이 유일하게 결정된다. 이를 X가 Y를 함수적으로 결정한다 , Y가 X에 함수적으로 의존한다라고 말하며, 두 집합 사이의 이러한 제약 관계를 functional dependency라고 부른다. `X → Y`

    📝 함수적 종속 (functional dependency)
    • X값이 같다면 Y값도 같은, 두 집합 사이의 제약 관계
    • (X의 관점) X가 Y를 함수적으로/유니크하게 결정한다
    • (Y의 관점) Y가 X에 함수적으로 의존한다

    `dept_id`의 경우, 회사의 내규에 따라 달라진다. 만약 직원이 하나의 부서에만 속한다면 `X → Y`를 만족한다. 하지만 하나 이상의 부서에 속할 수 있다면 같은 X에 대해 여러 개의 Y가 존재할 수 있어 FD를 만족하지 않는다.
     
    functional dependency에도 여러 종류가 있다.

    • trivial FD : Y가 X의 부분 집합인 경우 `{a, b, c} → {c}`
    • non-trivial FD : trivial FD가 아닌 경우
    • partial FD : X와 같지 않은 X의 부분 집합이 Y를 결정하는 경우 `{emp_id, emp_name} → {birth_date}`
    • full FD : X와 같지 않은 X의 부분 집합이 Y를 결정하지 못하는 경우 `{stu_id, class_id} → {grade}`

     

    1NF

    before after

    1NF 전의 `card_id`를 보면 `Messi`가 복수의 값을 가진 것을 확인할 수 있다. 1NF는 속성값이 반드시 나눠질 수 없는 단일한 값이어야 한다. 따라서 이를 별도의 레코드로 분리해야 한다. 하지만 이로 인해 중복된 데이터가 생겼으며, 레코드를 유일하게 구분하는 key가 필요하다.
     

    2NF

    before after

    레코드를 유일하게 식별하기 위해서는 `{account_id, card_id}`가 복합 key가 되어야 한다. 하지만 non-prime 속성들은 `account_id`만으로 결정된다. 즉, `account_id`에 따라 값이 달라진다.
     
    2NF 전의 테이블의 모든 non-prime 속성들은 `{account_id, card_id}`에 partially dependent 하다. 2NF는 모든 non-prime 속성이 모든 key에 fully functionally dependent 해야 한다. 따라서 `card_id`를 별도의 테이블로 분리해야 한다. 하지만 여전히 `empl_id`와 `empl_name`에 중복된 데이터가 존재한다.
     

    3NF

    before after

    `empl_id`는`account_id`에 의해, `empl_name`은 `empl_id`에 의해 결정된다. 이를 식으로 표현하면 `account_id → empl_id → empl_name`이 되고, transitive FD*라고 부른다.

    *transitive FD : `X → Y`, `Y → Z`를 만족하고 Y와 Z가 key의 부분 집합이 아닐 때, `X → Z`다.

     
    3NF는 모든 non-prime 속성이 어떤 key에도 transitively dependent 하면 안된다. 즉, non-prime 속성 간의 FD가 있으면 안된다.
     

    BCNF

    before after

    은행별로 계좌의 등급이 상이하다. 국민 은행은 STAR, PRESTIGE, LOYAL, 우리 은행은 BRONZE, SILVER, GOLD의 등급을 갖는다.
     
    BCNF는 모든 non-trivial FD `X → Y`는 X가 super key여야 한다. `class`에 따라 `bank_name`값이 결정되지만, `class`는 레코드를 유일하게 구별하지 못한다. BCNF를 만족하기 위해서는 테이블을 분리해야 한다.

    🚨 반정규화는 정규화의 반대 개념이다. 과도한 조인은 데이터베이스의 성능 저하로 이어질 수 있기 때문에 데이터 중복과 조인 사이에서 적정 수준을 선택해야 한다.   
    ⭐ 정규화 종류
    • 1NF : atomic value
    • 2NF : full FD (= not partial FD)
    • 3NF : not transitive FD
    • BCNF : if `X → Y`, X = candidate key

    참고자료

    댓글