본문 바로가기

Database(DB)

데이터베이스 정규화란? (1NF, 2NF, 3NF, BCNF 정리)

 데이터베이스 정규화란 무엇이고 왜 하는 것일까? 데이터베이스를 설계하고 다루는 과정에서 정규화 과정을 제대로 거치지 않는다면 성능 문제 뿐만 아니라 데이터 불일치, 개발 및 유지보수의 어려움을 겪을 수도 있다.

 정규화는 데이터 삽입, 수정, 삭제 시 발생할 수 있는 문제 예방, 불필요한 데이터 중복으로 인한 공간 방지 등 데이터를 효율적으로 저장하고 관리하기 위해서 테이블을 구조화하는 작업이라고 할 수 있다. 정규화도 여러 단계로 나누어져 있는데 1차~3차까지 또는 1차~4차(BCNF) 정도까지 많이 사용되고 5차 단계는 대규모 시스템 설계에 사용되고 일반적인 경우에는 잘 사용되지 않는다고 한다.

 

 먼저 1차 정규화를 알아보자. 1차 정규화는 간단하다. 테이블의 모든 속성이 원자값(Atomic Value)를 가져야 한다는 것이다. 원자값이 뭐냐고? 즉, 하나의 셀에 하나의 값만 존재한다는 것이다. 아래에 보이는 테이블은 고객(Customer) 테이블인데 고객 번호인 customer_phone 속성에 두 개의 값이 들어간 것이 보인다. 또한 고객 주소에도 두 개의 값이 들어가있다. 지금처럼 한 속성일 때 뿐만 아니라 여러 속성의 튜플(행)들이 모두 2개, 3개 이상의 값들을 가진다면 데이터의 조회, 수정 등 작업이 어려워 지는 것은 뻔하다. 그렇기에 모든 속성의 값을 하나만 가지도록 하는 것이 1차 정규화 과정이다.

 

 1차 정규화 전(customers)

customer_id customer_name customer_phone customer_address
1 김호수 010-1234-2295 서울 관악구, 경기 하남시
2 이한나 010-5678-9955 대전 서구
3 장현우 010-6677-1333, 010-3391-5055 서울 강남구

 

 1차 정규화 후(customers)

customer_id customer_name customer_phone customer_address
1 김호수 010-1234-2295 서울 관악구
2 이한나 010-5678-9955 대전 서구
3 장현우 010-3391-5055 서울 강남구

 

 

 다음은 2차 정규화를 살펴보자. 2차 정규화는 데이터 중복으로 인해 발생하는 이상현상(Anomaly)을 줄이는데 초점을 맞춘다. 그러면 이상현상이란 무엇일까? 예를 들어서 학생 정보 및 수강 과목 정보를 담은 학생 수강 과목 테이블이 있다고 가정해 봅시다. 아래 테이블이 잘 만들어진 구조일까요? 만약 과목명(course_name)이 바뀌면 여러 행에서 수정해야하고 일부 행만 수정하게 된다면 데이터 불일치가 발생하게 됩니다. 이를 갱신 이상(Update Anomaly)이라고 합니다. 이 뿐만 아니라 새로운 수강 과목이 개설되어서 추가하려고 했는데 아직 수강 신청을 한 학생이 없다고 하면 해당 테이블에 수강 과목 정보를 삽입하지 못하는 문제가 발생합니다. 이를 삽입 이상(Insertion Anomaly)라고 합니다. 그리고 수강 과목을 듣는 학생이 한 명인데 그 학생이 수강 과목을 취소한다면(아래의 테이블에서는 C111인 데이터베이스,  C107인 운영체제) 에 해당하는 과목 자체에 대한 정보가 사라지게 됩니다. 이를 삭제 이상(Deletion Anomaly)라고 하죠.

 이와 같은 이상 현상 및 문제들을 해결하기 위해서 모든 비(非)주요 속성(Non-key Attribute)이 기본 키(Primary Key) 전체에 대해 완전 함수 종속(Fully Functionally Dependent)이어야 한다는 규칙을 갖추게 하는 것이 바로 2차 정규화입니다. 이 테이블에서 student_id와 course_id가 복합 기본키인데 보시다시피 course_name은 course_id에만 종속이 됩니다. 기본 키 중 하나인 student_id 에는 전혀 종속되지 않는 것이지요. 즉 부분 함수 종속이 일어나고 있습니다. 반면 grade는 student_id와 course_id를 모두 알아야 알 수 있기 때문에 완전 함수 종속입니다.

 

 2차 정규화 전(student_course_grades)

student_id course_id course_name grade
001 C111 데이터베이스 B
001 C105 자료구조 A
002 C102 프로그래밍 B
002 C105 자료구조 B
003 C107 운영체제 A
004 C102 프로그래밍 C

 


 기본 키가 아닌 속성이 기본키 전체에 완전히 종속되게 수정한 테이블은 아래와 같습니다. 이렇게 부분 함수 종속을 가지고 있는 속성들을 한 테이블에 두지 않고 테이블을 분리하여 비 주요 속성들이 기본 키에 완전 함수 종속을 가지게 만들어서 발생할 수 있는 이상 현상을 없애고 성능 향상, 유지보수에 용이하게 테이블을 설계할 수 있습니다.

 

2차 정규화 후(student_courses)

student_id course_id grade
001 C111 B
001 C105 A
002 C102 B
002 C105 B
003 C107 A
004 C102 C

 

2차 정규화 후(courses)

course_id course_name
C111 데이터베이스
C105 자료구조
C102 프로그래밍
C107 운영체제

 

 

 

 3차 정규화(Third Normal Form, 3NF)는 2차 정규화를 만족하면서 기본키가 아닌 속성들이 이행적 함수 종속(transitive dependency)되지 않게 하는 것이다. 

 그렇다면 이행적 함수 종속성은 무엇일까요? A → B, B → C일 때, A → C가 성립하는 관계를 말하는데요, 3차 정규화는 이 A → C와 같은 이행적 함수 종속 관계를 제거하여 데이터의 중복을 줄이고, 삽입/갱신/삭제 이상(Anomaly)을 방지하는 것을 목표로 합니다(앞의 2차 정규화에서 이상 현상에 대해서는 설명을 하였습니다). 즉, 제2정규형을 만족하면서, 기본키에 속하지 않는 모든 속성(컬럼)들이 기본키에 이행적 함수 종속(Transitive Functional Dependency)되지 않도록 테이블을 분해하는 과정을 의미하며 쉽게 말해,  기본키가 아닌 속성들끼리 서로를 결정하는 관계(이행적 함수 종속)를 없애는 것이라고 할 수 있습니다.

 말로만 하는 것보다 직접 보는 것이 이해가 잘 될 수 있으니 테이블을 통해서 3차 정규화 과정을 살펴봅시다.

 

3차 정규화 전 (student_courses)

student_id student_name course_id course_name
1001 최연아 21 선형대수
1002 김대호 15 유체역학
1003 오세돌 11 알고리즘

 

 위 테이블에서는 학과번호, 학생이름, 학과코드, 학과이름이 나와 있습니다. 그냥 봤을 때는 문제가 없는 것 같아 보일 수 있지만 기본 키인 student_id(학과번호)가 학과이름을 결정하지 않고 학과코드를 통해 결정된다는 것을 알 수 있습니다. 이처럼 기본키에 직접 종속되지 않고 다른 비기본키에 이행 함수종속이 일어나지 않게 3차 정규화를 진행하는 것입니다. 이를 통해 데이터 이상 현상 방지, 데이터 중복 최소화 등 장점을 취할 수 있습니다.

 

3차 정규화 후 (students)

student_id student_name course_id
1001 최연아 21
1002 김대호 15
1003 오세돌 11

 

3차 정규화 후 (courses)

course_id course_name
21 선형대수
15 유체역학
11 알고리즘

 

 위와 같이 3차 정규화는 테이블 내 이행적 종속을 제거해 속성이 직접적으로만 키에 의존하도록 분해하였습니다. 물론 정규화가 무조건 장점만을 가진 것은 아닙니다. 이와 같이 테이블을 분리하면서 복잡성이 증가할 수 있고 데이터 조회 시 여러 테이블을 조인해야 하고 복잡한 쿼리로 성능 저하의 감소를 겪을 수도 있습니다. 그래서 정규화가 된 테이블의 성능을 개선하기 위해서 역정규화하는 과정을 거치기도 하기 때문에 목적에 맞게 잘 사용하면 될 것 같습니다.

 

 마지막으로 알아볼 정규화 과정은 BCNF(보이스-코드 정규형, Boyce-Codd Normal Form) 입니다. BCNF는 앞서 나온 3차 정규화보다 더 엄격한 정규화 과정으로써 모든 결정자(Determinant)가 후보키(Candidate Key)여야 한다는 조건을 가집니다. 결정자어떤 속성이 다른 속성을 유일하게 결정할 수 있는 것을 결정자라고 합니다. 후보키튜플을 유일하게 식별할 수 있는 속성 또는 속성 조합입니다. 예시 테이블을 통하여 살펴봅시다. 

 

정규화 전

student_id course_id instructor
1001 CS101 Kim
1002 CS101 Kim
1003 CS102 Lee

 

 정규화 전의 테이블을 보면 course_id가 instructor를 결정할 수 있는 결정자인 것을 알 수 있습니다. 하지만 이 학과코드가 모든 튜플을 유일하게 식별할 수 있는 속성, 후보키는 아닙니다. 후보키는 후보키 값으로 각 행을 유일하게 구별할 수 있어야 하는데 course_id 만으로 각 행들을 나누는 기준이 되지는 못합니다. 이 테이블에서 후보키는 (student_id, course_id)입니다. 즉 결정자가 후보키가 되지 못하기 때문에 BCNF 위반입니다.

 

정규화 후(courses)

course_id instructor
CS101 Kim
CS102 Lee

 

정규화 후(enrollments)

student_id course_id
1001 CS101
1002 CS101
1003 CS102

 

 이렇게 정규화를 거쳐 테이블을 나누었고 이제 각각의 결정자인 course_id (course_id → instructor) , student_id(student_id → course_id )가 유일성과 최소성을 갖춘 후보키(각 행들을 구분)가 되면서 BCNF 정규화를 위반하지 않습니다.

 

 지금까지 데이터 무결성 유지, 이상 현상 방지 등을 위해 자주 사용하는 정규화들에 대해서 알아보았습니다.