본문 바로가기

CS/데이터베이스

[데이터베이스] Informal Design Guideline for relational database

Informal Design Guideline

relational database의 디자인은 속성(attribute) 들이 "좋은" relation schema를 가지도록 만드는 작업이다. 이때 relation schema 에는 2개 레벨이 존재하며, 좋은 relation schema를 해당 계층에 대해 논할 수 있을 것이다.

  • Logical "user view" level
    : 유저가 relation schema와 그들의 의미를 해석하는 계층. 유저에게 노출되는 계층.
  • Storage "base relation" level
    : base relation 안의 튜플들이 저장 및 업데이트 되는 계층.

데이터베이스 디자인을 위한 가이드라인은 대략 다음과 같다.

  1. relation의 각 튜플들은 하나의 entity 혹은 relation을 나타내는 인스턴스여야 한다.
  2. update anomaly가 발생하지 않도록 스키마를 설계하고, 문제 발생 시 고쳐라.
  3. 타당하지 않은 NULL을 줄이고, 자주 발생하면 독립적인 relation으로 분리해라.
  4. 데이터를 분리하고 다시 join할때 데이터의 증감이 있어서는 안된다.

1. relation의 각 튜플들은 하나의 entity 혹은 relationship을 나타내는 인스턴스여야 한다.

 모듈을 만들때와 마찬가지로, relation을 설계하는 과정에서 각각에 대한 응집도(cohesion) 은 강하게 설정하여 속성 간 관계성을 강화해야 하고 relation 사이의 연관도(coupling)은 약하게 만들어 의존도를 낮추는 방향으로 설계한다.

 예를 들어 EMPLOYEE, DEPARTMENT 라는 mini-world의 개체들이 있다고 생각해보자. 이 둘은 명확한 의미( 직원 / 부서 ) 를 가지고 있으므로 각각을 묶어 EMP_DEPT 처럼 표현하기 보다는 그대로 표현하는 편이 좋다.

  • 다른 엔티티 사이들의 내용을 섞으면 안된다.
  • Foreign Key 만이 다른 엔티티를 참조하는데 사용되어야 한다. ( 일반 키는 X )
  • entity 와 relationship은 가능한 한 각각 존재하며, 이들 사이는 PK-FK 레퍼런스로 동작해야 한다.

2. update anomaly가 발생하지 않도록 스키마를 설계하고, 문제 발생 시 고쳐라.

Anomaly ( 이상 현상 )

 anomaly는 부자연스러운 것, 이상한 것을 의미하는 단어이다. 데이터베이스에서는 잘못된 스키마 설계로 인해 발생하는 이상 현상을 나타낸다. base relation을 natural join 할 때 설계를 잘 해뒀다면 삽입 이전의 데이터로 복구될 수 있지만, 설계상에서 문제가 있는 경우 anomaly가 발생하여 원래 데이터를 얻을 수 없게 된다. 따라서 이런 현상이 발생했다면 반드시 수정해야 한다.

 보통 Anomaly는 엔티티 사이에 데이터의 중복이 발생하는 경우 ( redundant information ) 발생한다. 데이터의 중복은 저장소를 낭비시켜 스토리지 비용을 늘리기도 하므로 최대한 줄여야 한다.

Update Anomaly는 크게 3가지로 분류된다.

Insert Anomaly( 삽입 이상 )

다른 속성을 삽입하지 않고서는 특정 속성을 삽입할 수 없는 상태를 의미한다. 위 그림의 EMP_PROJ는 EMPLOYEE의 내용과 PROJECT의 내용을 동시에 가지고 있다. 만약 EMPLOYEE와 PROJECT을 따로 구성하지 않고 위처럼 하나의 엔티티로 정의하여 사용한다고 가정하자. 이 상황에서 프로젝트에 참여하지 않은 사원을 저장할 수 있을까?

 Eid 및 Pid는 각각 EMPLOYEE 및 PROJECT의 Primary Key을 의미하는데, EMP_PROJ은 두개가 함께 Primary Key을 구성하므로 직원에게는 반드시 대응되는 프로젝트가 존재해야만 한다. 따라서 이런 엔티티로는 프로젝트에 참여하지 않는 직원 혹은 구상만 된 프로젝트를 표현하기 힘들다. 이런 현상은 분리되어야 할 엔티티가 하나로 묶여 발생한다.

Delete Anomaly( 삭제 이상 )

 여러 속성이 묶여, 하나의 속성이 제거될 때 연관된 속성도 같이 제거되어야 하는 상황을 의미한다. EMP_PROJ에서 직원 및 프로젝트 정보는 묶여 있으므로 직원을 제거하면 프로젝트 정보 역시 함께 제거된다. 이때, 특정 프로젝트의 직원이 모두 빠지고, 다른 인원들로 채워지는 상황을 생각해보자. 프로젝트와 연관된 직원을 모두 제거하는 경우, 어떤 한 순간에는 프로젝트 자체가 데이터베이스 내에 존재하지 않는 상태가 발생한다. 반대로 특정 프로젝트 정보를 모두 삭제하기 위해서는 관련된 직원 정도 전부 제거된다. 

 현실로 따지면 프로젝트가 끝나 전체 정보를 정리하는데, 해당 프로젝트와 관련된 모든 직원을 해고하는 셈이 된다. 이러한 anomaly는 의도하지 않은 정보의 제거를 불러올 수 있다.

Modification Anomaly( 갱신 이상 )

 하나의 정보를 수정하기 위해 관련된 모든 튜플의 정보를 수정해야 하는 이상 현상을 의미한다. 예를 들어 Pid = 1인 프로젝트의 이름이 A에서 B로 변했다고 생각해보자. EMP_PROJ에서 프로젝트의 이름은 동일 Pid를 가진 튜플들에 모두 중복되어있는 상태이므로, 하나의 튜플에서만 이름을 바꾸면 데이터의 일관성(consistency) 이 손상된다. 따라서 Pid = 1 인 모든 튜플의 이름을 A에서 B로 바꿔야 하는 상황이 발생한다. 이는 근본적으로 데이터 중복이 원인이 된다.

 이러한 Anomaly들이 발생했다는 것은 데이터베이스 스키마의 설계 단계에서 문제점이 존재해 이로 인한 중복이 있었음을 의미한다. 따라서 위 현상이 발생하면 반드시 데이터베이스 스키마의 구조를 수정하는 절차를 밟아야 한다.


3. 타당하지 않은 NULL을 줄이고, 자주 발생하면 독립적인 relation으로 분리해라.

NULL

NULL은 특정한 값이 없음을 나타내는 방식 중 하나이다. 구체적으로 다음 세가지 중 하나의 의미를 가진다.

  • 해당되지 않거나 불가능하다. ( not applicable or invalid ) 
    ex) 한국인에게 한국 비자를 묻는 경우
  • 알려져있지 않다. ( unknown / may exist )
    ex) 직원의 생일을 모르는 경우
  • 존재하기는 한데 현재 시점에서는 모른다. ( known to exist but unavailable )
    ex) 전화를 사용하는 것은 봤는데, 전화번호를 기록하지 않은 경우

 위 세가지 상황이 아닌 경우 NULL을 사용하는 것은 타당하지 않다. 이 경우 NULL을 없애는 방향으로 스키마 설계를 다시 수행해야 한다.

 위 상황에 맞는 NULL을 사용하더라도 전체적으로 NULL이 많이 발생한다면, 차라리 relation을 별개의 relation으로 분리한 후 이후 Join 조건을 통해 묶는 것이 나은 경우도 있다.

 요즘 시대에는 다들 애완동물을 많이 키운다고 해서 직원 정보와 직원의 애완동물 정보를 함께 관리한다고 생각해보자. 사장의 생각과는 달리 애완동물을 키우는 사원의 비율이 10%정도 밖에 안되는 경우, P_name 과 P_age는 전체 사원의 90%에 대해 NULL로 채워진다. 이때 NULL은 펫의 유무에 따라 지정되는 것이므로 NULL 사용 자체는 타당하지만 직원 정보와 함께 다루기에는 전반적인 공간의 낭비가 크다고 볼 수 있다. 이런 상황에서는 EMP_PET relation을 차라리 EMPLOYEE와 PET으로 독립한 후 둘을 PK-FK를 통해 연결하는 편이 저장소 활용에 도움이 될 것이다.

4. 데이터를 분리하고 다시 join할때 데이터의 증감이 있어서는 안된다.

 relational database의 설계가 잘못된 경우 분리된 relation들을 다시 join하여 원래 데이터를 만들 때 데이터가 줄거나 늘어날 수 있다. 이때 데이터가 줄거나 늘어나는 상황에 대한 용어가 존재한다.

lossless join

 분리된 데이터들을 join을 통해 결합할 때 정보의 손실이 없는 상황을 의미한다. 정보의 손실이란 존재하지 않는 정보가 추가되거나, 존재하던 정보가 사라지는 상황을 의미한다. 즉 정보에서의 증감이 있다면 정보의 손실이 발생하는 것이다. 따라서 lossless join은 나눠진 데이터들을 join 해서 원래 데이터를 재현할 수 있을때만 가능하다.

Spurious tuple

 relation들을 natural join을 통해 결합할 때 기존에 비해 새로 생성되는 튜플을 의미한다. 상식적으로 동일한 데이터를 나눴다가 다시 결합했다고 새로운 튜플이 생성되어서는 안된다. 따라서 이런 튜플들이 생성되었다는 것은 relation의 설계가 잘못되었음을 의미한다.

 모든 relation들은 다음과 같은 조건을 만족해야 한다.

  • relation은 lossless join 조건을 만족해야 한다.
  • spurious tuple이 natural join 과정에서 생성되어서는 안된다.

궁극적으로는 join을 수행할 때 다음 조건을 만족해야 한다.

  • Non Additive (추가 안됨) , losslessness (정보 손실 없음)
  • Functional Dependencies 보존

 단, 함수 종속의 경우 일부 상황에서 소실될 수도 있다. 때로는 소실된 함수 종속 관계를 데이터베이스 수준에서 복구시킬 수 없는 경우가 존재하는데, 이 상황에서는 어플리케이션 수준에서 반드시 함수 종속을 되살려서 나타낸다.