상위 문서: Relational Database Design
개요
헤당 문서에서는 관계형 데이터베이스를 설계할 때 사용되는 여러 가지 서로 다른 정규형(normal form)들 중에서 가장 일반적으로 사용되는 두 가지를 다룬다.
Boyce–Codd Normal Form
Boyce–Codd Normal Form(BCNF)는 함수 종속성에 기반하여 발견할 수 있는 모든 중복(redundancy)을 제거한다. 릴레이션 스키마(relation scema) R이, 함수 종속성(function dependency) 집합 F에 대해, 다음 조건을 만족하면 R은 BCNF에 있다고 한다:
α → β가 자명한 함수 종속성(trivial functional dependency)이어야 한다.[1]- α가 R 스키마에 대한 슈퍼키(superkey)이어야 한다.
또한, 데이터베이스 설계 전체가 BCNF에 있다(in)고 하려면, 그 설계를 구성하는 모든 릴레이션 스키마 각각이 BCNF에 있어야 한다.
예를 들어, 아래와 같은 릴레이션 스키마를 고려하자:
in_dep (ID, name, salary, dept_name, building, budget)
해당 릴레이션에서는 dept_name → building, budget 이라는 함수 종속성이 성립하지만 dept_name은 슈퍼키가 아니다.[2] 즉, 해당 릴레이션은 BCNF에 있지 않다(not in). 따라서 해당 릴레이션은 in_dep를 instructor와 department로 분해하는 것이 더 나은 설계이다. 그 이유는 아래와 같다:
- Instructor 스키마는 BCNF에 있다.
- instructor에서의 모든 비자명(nontrivial) 함수 종속성:
ID → name, dept_name, salary - 이때 튜플의 모든 속성값은 ID 속성의 값을 통해 추적할 수 있으므로, ID는 슈퍼키이다.
- instructor에서의 모든 비자명(nontrivial) 함수 종속성:
- Department 스키마도 BCNF에 있다.
- department 스키마에서의 비자명 함수 종속성:
dept_name → building, budget - 마찬가지로 dept_name은 슈퍼키이고, 따라서 department 역시 BCNF에 있다.
- department 스키마에서의 비자명 함수 종속성:
Decomposing a Schema into BCNF
BCNF에 있지 않은 스키마를 분해하기 위해서는 아래의 일반 규칙을 따라야 한다.
스키마 R이 BCNF에 있지 않으면, 반드시 하나 이상의 비자명 함수 종속성 α → β가 존재하며, 이때 α는 R의 슈퍼키가 아니다.
이 경우, R을 두 개의 스키마 R1, R2로 대체(replace)한다:
R1 = (α ∪ β)
R2 = (R − (β − α))
이를 위의 in_dep 릴레이션을 분해하는데 적용하면 α = dept_name, β = {building, budget}이다. 따라서 아래와 같다:
(α ∪ β) = (dept_name, building, budget) (R − (β − α)) = (ID, name, dept_name, salary)
이때 스키마를 한번 분해했더라도, 새로 생긴 스키마 중 하나 이상이 여전히 BCNF에 있지 않을 수 있으며, 그런 경우에는 분해를 반복해야 한다.
BCNF and Dependency Preservation
경우에 따라 BCNF로 분해하는 과정이 특정 함수 종속성의 효율적인 검사를 방해할 수 있다. 예를 들어, BCNF의 규칙을 따라 릴레이션을 분해하는 것은 종속성 보존(dependency preservation)을 어길 수 있다. 예를 들어, 다음 dept_advisor 스키마를 고려해보자:
dept_advisor (s_ID, i_ID, dept_name)
이 경우, 다음과 같은 함수 종속성이 성립한다고 가정하자:
- i_ID → dept_name: 교수는 오직 하나의 학과에 대해서만 지도교수 역할을 한다.
- (s_ID, dept_name) → i_ID: 학생은 주어진 학과에 대해 최대 한 명의 지도교수만 가질 수 있다.
해당 설계에서는 하나의 교수가 dept_advisor 릴레이션에 여러 번 등장할 때마다 학과 이름(dept_name)을 반복 저장해야 한다. 또한 i_ID가 슈퍼키가 아니기 때문에 dept_advisor는 BCNF가 아니다. 따라서, BCNF 분해 규칙에 따라 dept_advisor를 다음 두 스키마로 분해해야 한다.
(s_ID, i_ID) (i_ID, dept_name)
이 두 스키마는 모두 BCNF에 있다.[3] 하지만 문제는 BCNF로 분해한 후, (s_ID, dept_name) → i_ID라는 함수 종속성을 하나의 릴레이션만으로 검사할 수 없다는 점이다. 즉, (s_ID, dept_name) → i_ID를 검사하기 위해서는 분해된 두 릴레이션을 join 연산을 해서 다시 합쳐야만 가능하다. 즉, BCNF 분해를 하였을 때, 종속성 보존(dependency preservation)이 이루어지지 않았다.