비정규화 vs 정규화 데이터 베이스
정규화 데이터베이스는 중복을 최소화하도록 설게된 데이터베이스를 말합니다. 비정규화 데이터베이스는 읽는 시간을 최적화하도록 설계된 데이터베이스를 말합니다.
정규화는 데이터 중복을 최소화하고 데이터 무결성을 보장하기 위해 데이터를 여러 테이블로 나누는 과정을 정규화라고 합니다. 이를 간단한 예시를 기반으로 설명해보겠습니다. 예를들어, 특정 사용자가 주문한 주문 정보와 사용자 정보에 대해서 다룬다고 가정을 해보겠습니다.
| 주문ID | 고객ID | 이름 | 이메일 | 전화번호 | 주문일자 | 배송주소 |
|---|---|---|---|---|---|---|
| 101 | 1 | 김철수 | <kim@email.com> | 010-1234-5678 | 2025-03-10 | 서울시 강남구... |
| 102 | 2 | 이영희 | <lee@email.com> | 010-2345-6789 | 2025-03-12 | 부산시 해운대구... |
| 103 | 3 | 김철수 | <kim@email.com> | 010-1234-5678 | 2025-03-15 | 서울시 강남구... |
위와 같이 주문에 필요한 정보를 하나의 테이블에 관리하는 방법이 있을 것입니다. 비정규화 데이터베이스는 테이블 내의 데이터 탐색을 위하여 의도적으로 한 개의 데이터베이스에 여러 데이터를 중복을 고려하지 않고 저장하는 방법을 이야기 합니다.
위와 같이 테이블을 관리할 경우의 이점은 데이터를 읽어오기 편하다는 장점이 있습니다. 예를들어, 특정 고객이 주문한 정보를 읽어오는 과정에서 사용자의 정보를 동시에 읽어올 수 있기 때문에 추가적인 작업이 없이도 빠르게 조회가 가능하다는 장점이 있습니다.
하지만 위와 같이 데이터를 관리할 경우의 단점 또한 존재합니다. 모든 데이터들이 강하게 결합이 되어 있기 때문에 특정 데이터에 대해서 수정, 업데이트, 새로운 데이터를 등록해야 할 경우 모든 테이블의 데이터를 손봐야 한다는 문제가 있습니다. 이외에도 여러 문제가 있지만 우선 여기까지만 이야가하고 아래에서 더 자세하게 다루어보겠습니다. 그럼 이제 정규화를 수행했을 경우의 데이터에 대한 예시입니다.
- 고객 테이블
| 고객ID | 이름 | 이메일 | 전화번호 |
|---|---|---|---|
| 1 | 김철수 | <kim@email.com> | 010-1234-5678 |
| 2 | 이영희 | <lee@email.com> | 010-2345-6789 |
| 3 | 박지민 | <park@email.com> | 010-3456-7890 |
- 주문 테이블
| 주문ID | 고객ID | 주문일자 | 배송주소 |
|---|---|---|---|
| 101 | 1 | 2025-03-10 | 서울시 강남구... |
| 102 | 2 | 2025-03-12 | 부산시 해운대구... |
| 103 | 1 | 2025-03-15 | 서울시 강남구... |
위와 같이 정보를 한 가지의 테이블에 저장하지 않고 여러 개의 테이블로 나누어 관리하는 것을 정규화 데이터베이스라고 하고 이 정규화 데이터베이스는 무결성을 향상시키는 용도로 주로 사용이 됩니다.
정규화 데이터베이스의 경우 쿼리의 복잡성이 증가한다는 문제점이 있습니다. 예를들어 "김철수" 고객의 주소를 읽어오기 위해서는 고객 테이블에서 고객 ID를 불러오고 해당 ID 를 사용하여 주문 테이블에서 주문 정보를 불러와야 하는 과정이 필요합니다.
이러한 과정은 앞선 비정규 테이블에 비해서 훨씬 복잡해졌다는 것을 알 수 있습니다. 하지만 이렇게 데이터를 관리할 경우 데이터의 무결성을 지키기에는 훨씬 유리하다는 장점이 있습니다. 위와 같이 데이터를 다루면 중복된 데이터가 발생하지 않는 장점이 있습니다. 이제 이러한 비정규화 정규화 테이블의 특징들에 대해서 자세하게 다루어보겠습니다.
비정규화 데이터베이스의 주요 특징
비정규화 데이터베이스는 앞서 언급한 '빠른 조회'라는 강력한 장점이 있지만, 데이터 관리 측면에서 명확한 한계를 지닙니다.
-
장점
- 빠른 조회 속도: 데이터를 읽어올 때 여러 테이블을 연결(JOIN)할 필요가 없으므로 디스크 I/O 작업이 줄어들고 조회 속도가 매우 빠릅니다.
- 쿼리 단순화: 복잡한 JOIN 연산이 생략되므로 개발자가 작성해야 할 SQL 쿼리문이 단순해지고 직관적이게 됩니다.
-
단점
-
데이터 이상 현상(Anomaly) 발생 위험: 데이터가 강하게 결합되어 있고 중복 저장되어 있기 때문에 삽입, 수정, 삭제 시 무결성이 훼손될 수 있습니다.
- 수정 이상(Update Anomaly): '김철수' 고객의 이메일이 변경될 경우, 101번과 103번 주문 데이터에 있는 이메일을 모두 수정해야 합니다. 이때 단 하나라도 수정이 누락되면 동일한 사람임에도 이메일 정보가 일치하지 않는 모순이 발생합니다.
- 삽입/삭제 이상(Insert/Delete Anomaly): 아직 주문을 한 번도 하지 않은 신규 고객을 테이블에 추가하려면 주문 정보가 없으므로 불필요한 빈값(NULL)을 넣어야 하며, 반대로 고객의 특정 주문 내역 하나만 삭제하려다가 고객의 기본 정보까지 통째로 날아가는 문제가 발생할 수 있습니다.
-
저장 공간 낭비: 동일한 데이터(고객 이름, 이메일, 전화번호 등)가 주문이 발생할 때마다 반복해서 저장되므로 스토리지 공간을 비효율적으로 차지합니다.
-
-
적합한 사용 사례
- 데이터의 변경(삽입, 수정, 삭제)보다는 조회(읽기) 작업이 압도적으로 많이 발생하는 시스템.
- 과거의 데이터를 모아두고 분석하는 데이터 웨어하우스(Data Warehouse) 및 OLAP(온라인 분석 처리) 시스템.
정규화 데이터베이스의 주요 특징
정규화는 제1정규형(1NF)부터 시작하여 제2정규형(2NF), 제3정규형(3NF), BCNF 등 정해진 수학적 규칙과 단계에 따라 데이터의 종속성을 해결하고 중복을 제거해 나가는 객관적인 과정입니다.
제1정규형(1NF)
모든 속성이 원자 값(atomic value)를 가져야 합니다. 원자 값은 더 이상 논리적으로 분해될 수 없는 값을 의미합니다.
제 2 정규형(2NF)
1NF를 만족하며, 비주요 속성이 주요 속성에 완전 함수적 종속이어야 합니다. 이에 대해서 자세하게 설명 해보겠습니다.
함수적 종속성은 X -> Y로 표기하며, X가 Y를 함수적으로 결정한다는 것을 의미합니다. 이는 X를 알면 Y를 알 수 있다는 것을 의미합니다. 예를 들어 학번이 학생 이름을 결정한다면 학번 -> 학생 이름으로 표현할 수 있습니다.
완전 함수적 종속(Full Functional Dependency) 은 속성 집합 X와 속성 Y가 있을 때, Y가 X 전체에 함수적으로 종속되어 있고, X의 어떤 진부분집합(proper subset)에도 종속되지 않는 경우입니다. 즉, X의 모든 속성이 Y를 결정하는 데 필요합니다.
부분 함수적 종속(Partial Functional Dependency) 은 복합 속성 X(여러 속성으로 구성된)에서 Y가 X의 일부분만으로도 결정될 수 있는 경우입니다. 즉, X의 모든 속성이 Y를 결정하는 데 필요하지 않은 경우입니다.
기본 키와는 테이블의 각 행을 유일하게 식별할 수 있는 속성 또는 속성의 집합입니다. 후보키는 기본 키가 될 수 있는 모든 속성 또는 속성의 집합을 말합니다.
- 주요 속성(Prime Attribute): 어떤 후보키의 구성 요소가 되는 속성
- 비주요 속성(Non-prime Attribute): 어떤 후보키의 구성 요소도 아닌 속성
이제 다시 제 2 정규형에 대해서 다시 생각해보겠습니다. 테이블에 복합키(여러 속성으로 이루어진 키)를 가진 경우, 모든 비주요 속성은 키의 일부가 아닌 전체 키에 종속되어야 한다는 것을 의미합니다.
| 학번 | 과목코드 | 학생이름 | 과목명 | 성적 | 학과 |
|---|---|---|---|---|---|
| S001 | C001 | 김학생 | 데이터베이스 | A+ | 컴퓨터공학과 |
| S001 | C002 | 김학생 | 자료구조 | B+ | 컴퓨터공학과 |
| S002 | C001 | 이학생 | 데이터베이스 | A | 정보통신공학과 |
위와 같은 수강 테이블이 있다고 가정해보겠습니다. 이 테이블에서 기본키는 학번, 과목코드의 복합키입니다. 그리고 이 테이블의 주요 속성은 학번, 과목 코드 입니다. 비주요 속성은 학생이름, 과목명, 성적, 학과가 비주요 속성에 해당합니다.
이 테이블의 함수적 종속성을 분석해보면
- (학번, 과목코드) → 성적 (완전 함수적 종속)
- 학번 → 학생이름 (부분 함수적 종속)
- 학번 → 학과 (부분 함수적 종속)
- 과목코드 → 과목명 (부분 함수적 종속)
(학번, 과목코드) -> 성적 관계가 성립하는 이유는 학번 만으로는 성적을 유일하게 결정할 수 없기 때문입니다. 학번에 해당하는 성적은 여러 개가 존재하기 때문입니다. 이는 과목 코드 또한 마찬가지이기 때문에 성적을 유일하게 결정하기 위해서는 학번과 과목 코드를 복합키로 사용해야 합니다.
학생 이름은 학번으로 유일하게 결정이 됩니다. 앞선 복합키에 포함되어 있는 과목 코드가 학생 이름을 결정 짓는데 필요하지 않습니다. 따라서 학생이름은 복합 키의 일부에만 종속이 되어 있습니다. 복합키(학번, 과목코드) 중에서 학번만으로도 학생이름이 결정되므로, 이는 부분 함수적 종속입니다.
현재 위의 테이블은 부분 함수적 종속이 존재하기 때문에 제 2 정규형(2NF) 를 만족하지 못하고 있습니다. 그렇기 때문에 제 2 정규형을 만족 시키기 위해서는 아래와 같이 변형 시켜야 합니다.
학생 테이블:
| 학번 | 학생이름 | 학과 |
|---|---|---|
| S001 | 김학생 | 컴퓨터공학과 |
| S002 | 이학생 | 정보통신공학과 |
과목 테이블:
| 과목코드 | 과목명 |
|---|---|
| C001 | 데이터베이스 |
| C002 | 자료구조 |
수강 테이블:
| 학번 | 과목코드 | 성적 |
|---|---|---|
| S001 | C001 | A+ |
| S001 | C002 | B+ |
| S002 | C001 | A |
이제 각 테이블에서 완전 함수적 종속을 만족 하기 때문에 제 2 정규형을 만족하고 있다고 할 수 있습니다. 이렇게 제 2 정규형을 만족해야 하는 이유는 다음과 같은 이상현상(Anomaly) 이 발생할 수 있기 때문입니다.
이상현상(Anomaly)
이상 현상은 데이터를 삽입, 수정, 삭제할 경우의 논리적인 오류가 발생하는 것을 이야기하며 주로 갱신 이상, 삽입 이상, 삭제 이상으로 구분이됩니다. 이러한 현상을 왜 삽입, 수정, 삭제의 경우의 특정 경우에만 이러한 현상이 발생하는 것일까요?
이러한 이상현상의 증상이 어떤 것인지에 대해서 자세하게 다루기 위해서는 한 가지 가정을 해야 합니다. 테이블의 데이터는 중복이 가능하고 각각의 테이블은 독립적이지 않으며 schema를 검증하지 않는다는 가정이 필요합니다. 이러한 가정하에 각각의 이상 현상에 대해서 설명해보겠습니다.
| 직원 ID | 직원 이름 | 부서 | 부서 전화번호 |
|---|---|---|---|
| 1 | 김철수 | 영업부 | 010-1234-5678 |
| 2 | 이영희 | 마케팅부 | 010-9876-5432 |
| 3 | 이영미 | 영업부 | 010-1234-5678 |
| 4 | 최지현 | 개발부 | 010-1122-3344 |
- 갱신 이상 : 중복된 데이터 중 일부만 수정되어 데이터 모순이 일어나는 현상, ex ) 위의 테이블에서는 영업부에 속한 부서 전화번호를 수정하려고 할 경우 모든 데이터가 수정되지 않는 현상
- 삽입 이상 : 자료를 삽입할 때 의도하지 않은 자료까지 삽입해야만 자료를 테이블에 추가가 가능한 현상, ex ) 위의 테이블에서 새로 삽입하는 직원의 부서가 정해지지 않아 해당 데이터는 추가에 업로드하려고 하지만 이를 추가하지 않으면 추가가 되지 않는 현상
- 삭제 이상 : 어떤 정보를 삭제하면, 의도하지 않은 다른 정보까지 삭제되어버리는 현상 ex ) 마케팅 부에 대한 정보를 삭제하려고 하는데 이영희의 정보까지 삭제가 되어 버리는 현상
이러한 이상 현상이 발생하기 때문에 제 2정규형을 지켜야 정규화된 데이터베이스, 중복을 최소화 할 수 있게 됩니다.
제 3 정규형
"비주요 속성 간의 이행적 종속성이 없어야 한다" 는 조건이 제 3정규형에서 핵심입니다. 이행적 종속성 이란 세 개의 속성(또는 속성 집합) A, B, C가 있을 때, 다음과 같은 두 가지 함수적 종속성이 존재하는 경우를 말합니다.
A -> B: A는 B를 결정한다B -> C: B는 C를 결정한다, 그리고B -> A가 성립하지 않는 상태를 의미합니다.
이로 인해 A -> C A는 C를 결정한다는 관계가 간접적으로 성립하게 되는 관계를 이행적 종속성 이라고 합니다.
제 3 정규형의 핵심은 비주요 속성이 기본키에 이행적으로 종속되지 않아야 한다는 것입니다. 즉, 모든 비주요 속성은 기본키에 종속되어야 하며, 다른 비주요 속성을 통해 간접적으로 종속되어서는 안됩니다.
| 학번(PK) | 학생이름 | 학과코드 | 학과명 | 학과장 |
|---|---|---|---|---|
| S001 | 김철수 | D001 | 컴퓨터공학과 | 박교수 |
| S002 | 이영희 | D001 | 컴퓨터공학과 | 박교수 |
| S003 | 박지영 | D002 | 화학공학과 | 김교수 |
| S004 | 최민수 | D003 | 기계공학과 | 이교수 |
위의 테이블을 예시로 생각을 해보겠습니다. 우선 위의 테이블에서 주요 속성과 비주요 속성을 구분하고 어떠한 관계를 갖는지 생각 해보겠습니다.
학번 -> 학생이름, 학번 -> 학과 코드, 학과코드 -> 학과명, 학과코드 -> 학과장 의 관계를 갖고 있음을 확인할 수 있습니다. 학번은 주요 속성에 해당하고 학과코드, 학과장, 학과명은 비주요 속성에 해당합니다.
이 관계에서 학번 → 학과코드 → 학과명, 학번 → 학과코드 → 학과장 의 관계가 확인되기 때문에 이행적 종속성을 갖고 있음을 확인할 수 있습니다. 이행적 종속성이 있을 경우 다음과 같은 문제를 갖게 됩니다.
앞서 제 2 정규형에서 발생한 문제와 동일한 문제가 발생합니다. 갱신 이상, 삽입 이상, 삭제 이상 그리고 데이터 중복 문제가 발생하게 됩니다. 이를 해결하기 위해서는 아래와 같이 테이블을 나누어줘야 합니다.
학생 테이블:
| 학번(PK) | 학생이름 | 학과코드(FK) |
|---|---|---|
| S001 | 김철수 | D001 |
| S002 | 이영희 | D001 |
| S003 | 박지영 | D002 |
| S004 | 최민수 | D003 |
학과 테이블:
| 학과코드(PK) | 학과명 | 학과장 |
|---|---|---|
| D001 | 컴퓨터공학과 | 박교수 |
| D002 | 화학공학과 | 김교수 |
| D003 | 기계공학과 | 이교수 |
비정규화 vs 정규화 요약 비교
각 설계 방식의 객관적인 차이는 다음과 같습니다.
| 구분 | 비정규화 (Denormalization) | 정규화 (Normalization) |
|---|---|---|
| 핵심 목적 | 읽기(Read) 성능 최적화 | 데이터 무결성(Integrity) 및 일관성 확보 |
| 데이터 중복도 | 높음 (중복 허용) | 낮음 (중복 최소화) |
| 조회(Read) 성능 | 빠름 (JOIN 연산 불필요) | 상대적으로 느림 (JOIN 연산 필요) |
| 갱신(Write) 성능 | 느림 (중복된 모든 데이터 탐색 및 수정 필요) | 빠름 (해당 테이블의 단일 레코드만 수정) |
| 이상 현상(Anomaly) | 발생 위험 높음 | 발생 위험 매우 낮음 |
결론적으로 데이터베이스 설계에 있어 무조건적으로 옳은 단일 정답은 없습니다. 시스템의 목적이 '데이터의 빠른 조회' 인지, 아니면 '데이터의 정확성과 무결성 유지' 인지 정확한 지표와 사실을 기반으로 판단해야 합니다. 실제 실무 환경에서는 정규화를 통해 데이터 무결성을 먼저 확보한 뒤, 조회 성능에 병목이 발생하는 특정 지점에 대해서만 의도적으로 중복을 허용하는 역정규화(Denormalization) 기법을 혼합하여 사용하는 것이 일반적입니다.
BCNF 및 그 이상의 정규형
제3정규형(3NF)을 만족하더라도 테이블 내에 여러 개의 후보키가 존재하는 경우, 후보키가 아닌 속성이 결정자 역할을 하게 되어 이상 현상이 발생할 수 있습니다. 이를 해결하기 위해 모든 결정자가 후보키가 되도록 테이블을 분해하는 **BCNF(Boyce-Codd Normal Form)**를 적용합니다. 이외에도 제4정규형(4NF), 제5정규형(5NF) 등이 존재하지만, 일반적인 실무 환경에서는 제3정규형이나 BCNF까지만 정규화를 진행하여도 대부분의 데이터 이상 현상을 방지할 수 있습니다.
결론: 정규화와 비정규화의 선택 기준
앞서 다룬 특징들을 종합해 볼 때, 정규화와 비정규화는 데이터베이스 설계에서 성능과 데이터 무결성 사이의 트레이드오프(Trade-off) 관계를 가집니다.
-
정규화(Normalization): 데이터의 일관성과 무결성을 보장하고 중복을 최소화합니다. 삽입, 수정, 삭제 등의 갱신 작업(Write)이 빈번한 시스템(예: OLTP 환경)에 필수적입니다. 단, 테이블이 과도하게 분리되면 조인(JOIN) 연산 증가로 인해 읽기 성능이 저하될 수 있습니다.
-
비정규화(Denormalization): 중복을 허용하는 대신 데이터의 읽기(Read) 성능을 극대화합니다. 데이터 분석을 위한 웨어하우스나 조회가 압도적으로 많은 시스템(예: OLAP 환경)에 적합하지만, 데이터 갱신 시 이상 현상(Anomaly)이 발생할 위험이 높습니다.
실무에서의 접근 방식 실제 데이터베이스를 설계할 때 둘 중 하나만을 극단적으로 선택하는 경우는 드뭅니다. 올바른 설계 원칙은 다음과 같습니다.
- 선(先) 정규화: 초기 설계 시에는 데이터의 무결성을 보장하기 위해 기본적으로 제3정규형(3NF) 또는 BCNF 수준까지 철저하게 정규화를 수행합니다.
- 후(後) 비정규화(역정규화): 시스템을 운영하며 성능 테스트를 진행한 후, 조회가 너무 빈번하게 발생하여 심각한 성능 병목이 확인되는 특정 구간에 대해서만 제한적으로 비정규화(테이블 병합, 중복 칼럼 추가 등)를 적용합니다.
결과적으로, 정규화를 통해 시스템의 안정성과 정확한 데이터 상태를 뼈대로 잡고, 필요한 곳에 비정규화를 도입하여 성능을 보완하는 혼합 전략을 사용하는 것이 가장 객관적이고 효율적인 데이터베이스 설계 방법입니다.