# 35강. 정규화
테이블을 올바른 형태로 변경하고 분할하는 것을 정규화라 한다.

- 정규화란 데이터베이스의 테이블을 규정된 올바른 형태로 개선해나가는 것이다.
- 정규화는 데이터베이스의 설계 단계에서 행해진다.
- 경우에 따라서는 기존 시스템을 재검토할 때 정규화하는 경우도 있다.
- 여기서 말하는 올바른 형태란 주관적 기준이라 할 수 있다.
- 정규화의 순서는 이전의 데이터베이스 기술자들이 고안해 정리한 것이다.
- 이를 참고하여 정규화하는 과정을 통해 관계형 데이터베이스가 효율적으로 동작하도록 만들 수 있다.
- 잘만 활용하면 효율적인 데이터베이스를 설계할 수 있다.

---

## 1. 정규화
먼저, 쇼핑 사이트의 주문처리 시스템을 구축해본다. 그에 앞서 간단한 주문데이터로는 어떤 것이 필요할지 생각해 본다.

**`간단한 주문 데이터`**

![35강 간단한 주문 데이터](https://user-images.githubusercontent.com/68052095/102682519-76cbae00-420d-11eb-8b7c-100d1c410ad2.PNG)

- 여기서 주문상품 부분이 특별한 형식 없이 대충 만들어진 것처럼 보여 문제가 될 수 있다. 따라서 상품은 상품코드를 이용해 다루도록 한다.
- '0001 OO 1개'라고 되어 있는 부분은 상품코드가 0001인 상품 OO를 1개 주문했다는 뜻이다.
- 물론 한번 주문할 때 여러 개의 상품을 주문할 수도 있다.
- 주문번호 1의 데이터를 살펴보면 '0001 OO이 1개, 0002 XX가 10개'로 두 가지 종류의 상품을 주문했다는 것을 알 수 있다.
- 이렇게 대충 만들어진 데이터를 정규화해 데이터베이스의 테이블로 만들어 본다.
- 정규화는 단계적으로 실시한다. 그 첫 번째 단계가 `제1 정규화`로, 이를 시행하면 제1 정규형 테이블을 만들 수 있다.

---

## 2. 제1 정규형
- 관계형 데이터베이스의 테이블에는 하나의 셀에 하나의 값만 저장할 수 있다는 제약이 있다.
- 이로 인해 주문상품의 데이터를 그대로 테이블로 만들 수는 없다.
- 적어도 상품코드와 상품명, 개수 데이터를 담는 세 개의 열로 나누어야 한다.

**`주문상품 데이터를 상품코드, 상품명, 개수로 분할하기`**

![35강 주문상품 데이터를 상품코드, 상품명, 개수로 분할하기](https://user-images.githubusercontent.com/68052095/102682517-76331780-420d-11eb-80d9-7225dce948e9.PNG)

- 위처럼 구분하면 하나의 셀에는 하나의 값만 저장되므로 테이블화 할 수 있다.
- 이때 테이블 이름은 '주문'이라 한다.
- 주문상품 데이터를 상품코드와 개수로 분할함에 따라 열이 두 개 더 추가되었고 행도 늘어난 것에 주목하자.
- 이렇게 하나의 셀에 하나의 값만 저장할 수 있도록 하고, 반복되는 부분을 세로(행) 방향으로 늘려나가는 것이 제1 정규화의 제 1단계이다.

##### 반복되는 데이터를 가로(열 방향)가 아닌 세로(행 방향)로 늘리는 것이 제1 정규화의 제1 단계이다!

- 제1 정규화에서는 중복을 제거하는 테이블의 분할도 이루어진다.
- 예를 들면 한번의 주문으로 여러 개의 상품을 주문할 수 있으므로 주문번호, 날짜, 성명, 연락처가 동일한 값을 가지는 행이 여러 개 존재할 수 있다.
- 이때 동일한 값을 가지는 행이 여러 개 존재하지 않도록 하나로 정리한다.
- 먼저, 주문 테이블을 주문상품 테이블과 주문 테이블로 나눈다.
- 주문 테이블은 주문번호, 날짜, 성명, 연락처로 구성한다.
- 한편 주문상품 테이블을 상품코드, 상품명, 개수로 구성하되, 추가적으로 주문 테이블과 결합할 수 있도록 주문번호 열을 추가한다.

**`주문 데이터를 주문 테이블과 주문상품 테이블로 분할`**

![35강 주문 데이터를 주문 테이블과 주문상품 테이블로 분할](https://user-images.githubusercontent.com/68052095/102682175-e0968880-420a-11eb-8b4d-f4cbb404368c.png)

- 그 결과 반복되는 부분이 하나로 깔끔하게 정리되었다.
- 이것으로 주문 데이터가 변경되더라도 한 군데만 수정하면 된다.
- 물론 분할 전 상태의 데이터를 원할 때에도 결합하면 되므로 아무런 문제가 없다.
- 여기에서 분할 이후의 주문 테이블을 자세히 살펴보면, 주문번호에는 중복된 값이 존재하지 않기 때문에 기본키로 지정할 수 있다.
- 한편 주문상품 테이블에서는 주문 번호와 상품코드를 한데 묶어 기본키로 지정할 수 있다.
- 이처럼 제1 정규화에서는 반복되는 부분을 찾아내서 테이블을 분할하고 기본키가 될 열을 작성할 수 있다.

##### 제1 정규화에서는 테이블 분할과 기본키 지정이 이루어진다!

---

## 3. 제2 정규형
- 제1 정규화에서 테이블에 기본키를 작성한 것과 같은 방법으로, `제2 정규화`에서는 데이터가 중복하는 부분을 찾아내어 테이블로 분할해 나간다.
- 이때 기본키에 의해 특정되는 열과 그렇지 않은 열로 나누는 것으로 정규화가 이루어진다.
- 주문상품의 기본키는 주문번호와 상품코드의 두 개 열로 되어 있다.
- 주문번호 1에 상품코드가 0001인 상품 주문량은 총 1개라는 것을 알 수 있다.
- 이것은 기본키를 바탕으로 특정되는 데이터이다.
- 즉, 개수 열은 기본키가 결정되고나면 특정할 수 있는 것이다.
- 한편 상품명은 주문번호와 관계없이 상품코드만으로 특정할 수 있다.
- 상품코드는 기본키의 일부이긴 하지만 단독으로 기본키 역할을 할 수는 없다.
- 이처럼 두 가지로 분류할 수 있으므로 두 개 테이블로 분할한다.
- 테이블명은 '상품'이라고 한다.

**`주문상품 테이블을 분할`**

![35강 주문상품 테이블을 분할](https://user-images.githubusercontent.com/68052095/102682174-e0968880-420a-11eb-81ab-df98ca225252.png)

- 상품 테이블은 상품코드만으로 기본키를 지정했다.
- 어려운 말로 표현하자면 부분 함수종속성을 찾아내서 테이블을 분할하는 것이 제2 정규화이다.
- 여기서 함수종속성이란 키 값을 이용해 데이터를 특정지을 수 있는 것을 가리킨다.

---

## 4. 제3 정규형
- 마지막으로 `제3 정규화`이다. 이 또한 중복하는 부분을 찾아내어 테이블을 분할하는 수법이다.
- 제2 정규화의 경우에는 기본키에 중복이 없는지 조사했지만 제3 정규화에서는 기본키 이외의 부분에서 중복이 없는지를 조사한다.

**`주문 테이블을 분할`**

![35강 주문 테이블을 분할](https://user-images.githubusercontent.com/68052095/102682173-dffdf200-420a-11eb-8fdd-b58c2b22b283.png)

- 분할하기 전의 주문 테이블을 살펴보면 데이터가 중복되어 있다.
- 같은 사람이 여러 번 주문하는 경우가 있기 때문이다.
- 이때 주문 테이블에서 이름을 기준으로 연락처를 특정지을 수 있다.
- 단, 주문 테이블의 기본키는 어디까지나 주문번호로, 이름은 기본키와는 관계가 없다.
- 한편 분할하여 새로 만들 테이블의 이름은 '고객'이라 붙였다.
- 여기서도 이름을 기본키로 지정하면 동명이인의 경우 데이터를 제대로 저장할 수 없으므로 고객번호를 기본키로 지정하여 고객 테이블을 작성했다.

실제로는 제5 정규형까지 있지만 대부분의 시스템에서 제3 정규형까지의 정규화를 채택한다.

**`정규화 후의 테이블`**

![35강 정규화 후의 테이블](https://user-images.githubusercontent.com/68052095/102682767-5d2b6600-420f-11eb-8bc0-453ffbecb662.jpg)

- 이처럼 정규화를 통해 테이블을 분할해 나간다.
- 분할할 때에는 서로 결합할 수 있도록 기본키를 추가해 분할한다.
- 테이블 간의 연계는 ER다이어그램으로 표현하면 알기 쉽다.

**`정규화 후의 테이블을 ER다이어그램으로 표기`**
![35강 정규화 후의 테이블을 ER다이어그램으로 표기](https://user-images.githubusercontent.com/68052095/102682172-df655b80-420a-11eb-92fc-db582bff38f2.png)

- ER다이어그램에서는 네모난 상자(엔티티)가 테이블을 의미한다.
- 테이블 간의 선이 연계(릴레이션십)을 의미하며 1대多, 多대1 등과 같은 다중도로도 표시한다.
- 주문상품 테이블과 상품 테이블 간의 연계(릴레이션십)에서는 상품 쪽이 1, 주문상품 쪽이 多로 1대多라는 다중도를 나타낸다.
- 즉, 주문상품 테이블 쪽의 데이터에서 상품 테이블을 보면 상품 테이블의 하나의 행을 특정하는 것이다.
- 이는 상품코드가 기본키인 만큼 당연한 일이다.
- 반대로 상품 테이블 쪽에서 주문상품 테이블을 보면 하나의 상품이 여러 번 주문되었기 때문에 상품코드를 이용해도 주문상품 테이블의 하나의 행만 특정할 수 없다.
- 다시 말해 여러 개의 행이 존재한다는 이야기이다.
- 그 밖에 주문상품의 상품코드에 (FK)라고 적혀 있는 것은 외부키 속성을 가진다는 의미이다.

---

## 5. 정규화의 목적
- 정규화에서는 중복하거나 반복되는 부분을 찾아내서 테이블을 분할하고 기본키를 작성해 사용하는 것을 기본 개념으로 삼는다.
- 이는 `하나의 데이터는 한 곳에 있어야 한다`는 규칙에 근거한다.

##### 정규화로 데이터 구조를 개선하는 것은 하나의 데이터가 한 곳에 저장되도록 하기 위함이다!

- 하나의 데이터가 반드시 한 곳에만 저장되어 있다면 데이터를 변경하더라도 한 곳만 변경하는 것으로 끝낼 수 있다.
- 반면 정규화되지 않은 경우에는 여기저기 중복해서 저장된 데이터를 검색하고 일일이 변경해야 한다.
- 이것은 매우 번거로운 작업이다.
- 또한 인덱스가 지정된 열의 데이터가 변경되는 경우에는 인덱스도 재구축해야 한다.
- 하지만 기본키는 분할한 테이블끼리 연계하기 위해 작성한, 이른바 내부적인 데이터이므로 변경될 일은 거의 없다.
- 따라서 정규화를 통해 테이블에 대한 인덱스의 재구축을 억제할 수 있다.

---