[SQL] 정규화(Normalization)
정규화란?
데이터베이스 정규화는 데이터베이스 내의 구조를 조직화하고 최적화하는 과정입니다
정규화를 하는 이유
- 데이터의 중복을 줄이고 데이터의 무결성을 보장한다
- 데이터 효율을 높인다
- 이상 현상을 방지한다
일반적으로 제1~3정규화를 진행합니다
이상현상
데이터 정규화를 하지 않은 데이터베이스는 다음과 같은 이상현상이 발생할 수 있습니다
👉 고객 정보와 주문 정보를 같은 레코드에 저장하는 데이터베이스를 예로 들면,
- 삽입 이상(Insertion Anomaly) : 새로운 데이터를 삽입할 때 원하지 않는 문제가 발생합니다
👉 새로운 고객을 등록하려 할 때, 주문 정보가 없어 삽입이 불가능 할 수 있다 - 삽입삭제 이상(Delete Anomaly) : 특정 데이터 삭제 시, 다른 데이터도 함께 손실되는 현상이 발생합니다
👉 고객의 정보를 삭제하면 그 고객에 대한 모든 주문 정보도 함께 삭제될 수 있다 - 갱신 이상(Update Anomaly) : 속상값 갱신 시 일부 값만 갱신되어 모순이 발생합니다
👉 한 고객이 주문을 여러 개 하고, 배송 주소를 변경할 때, 모든 주문의 배송 주소를 변경해주어야 함
따라서 데이터의 일관성을 유지하기가 어렵다
정규화의 종류
제1정규화(1NF)
1) 각 행을 유일하게 구분하는 컬럼이 존재합니다 -> Primary Key가 존재
2) 모든 데이터는 원자적으로 저장됩니다 -> 한 컬럼에 여러 값이 저장되지 않는다
Primary Key
1. NOT NULL이면서 UNIQUE 한 값이어야 한다
2. 바뀔 가능성이 현저히 낮아야 한다
3. 가장 좋은 PK는 의미없는 칼럼이다
강의 | 학생 |
국어 | 이상혁 |
수학 | 최우제, 이민형 |
영어 | 문현준, 류민석 |
위의 데이터에서 학생은 여러 개의 값을 가지고 있어 데이터를 원자적으로 저장한다는 조건을 만족하지 못한다.
번호 | 강의 | 학생 |
1 | 국어 | 이상혁 |
2 | 수학 | 최우제 |
3 | 수학 | 최우제 |
4 | 영어 | 문현준 |
5 | 영어 | 류민석 |
다음과 같이 수정하고 기본키(Primary Key)인 번호를 추가해주었다
CREATE TABLE lecture
(
id INT PRIMARY KEY AUTO_INCREMENT,
subject VARCHAR(10),
student VARCHAR(10)
);
제2정규화(2NF)
1) 제1정규화를 만족한다
2) 기본키의 부분집합이 결정자가 되어서는 안된다
학생이름 | 강좌이름 | 강의실 | 성적 |
안진아 | JAVA | 501 | B |
강동현 | JAVA | 501 | A |
박재형 | DB | 502 | A |
김예빈 | Python | 503 | A+ |
이 테이블에서 기본키는 학생이름+강좌이름으로 복합키이다. 그리고 학생이름과 강좌이름에 의해서 성적이 결정된다.
그런데 강의실은 기본키의 부분집합인 강좌이름에 따라 결정되고 있으므로 2번 조건을 만족하지 않는다.
따라서 다음과 같이 수정할 수 있다
학생이름 | 강좌이름 | 성적 |
안진아 | JAVA | B |
강동현 | JAVA | A |
박재형 | DB | A |
김예빈 | Python | A+ |
강좌이름 | 강의실 |
JAVA | 501 |
DB | 502 |
Python | 503 |
CREATE TABLE Students
(
student_name VARCHAR(10),
lecture_name VARCHAR(10),
grade VARCHAR(3)
PRIMARY KEY (student_name, lecture_name)
FOREIGN KEY (lecture_name) REFERENCES Classroom (lecture_name)
);
CREATE TABLE Classroom
(
lecture_name VARCHAR(10),
room_number VARCHAR(10)
);
제3정규화(3NF)
1) 제2정규화를 만족한다
2) 이행적 종속을 없애야 한다
이행적 종속이란?
A->B, B->C가 성립할 때, A -> C가 성립하는 것을 말한다
고객이름 | 고객등급 | 혜택 |
이상혁 | 1 | 무료배송 |
최우제 | 2 | 할인 |
문현준 | 3 | 라운지 |
이민형 | 2 | 할인 |
위의 테이블은 고객이름이 고객등급을 결정하고, 고객등급이 해당 등급에 따른 혜택을 결정하고 있다.
이는 이행적 종속을 삭제하는 조건 2를 만족하지 않기에 다음과 같이 수정할 수 있다
고객이름 | 고객등급 |
이상혁 | 1 |
최우제 | 2 |
문현준 | 3 |
이민형 | 2 |
고객등급 | 혜택 |
1 | 무료배송 |
2 | 할인 |
3 | 라운지 |
CREATE TABLE Customer
(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(3),
level INT,
FOREIGN KEY (level) REFERENCES Customer_benefit (level)
);
CREATE TABLE Customer_benefit
(
level INT PRIMARY KEY,
benefit VARCHAR(100)
);