まとめました。まとめ過ぎたかもしれません。正規化。

こんにちは、Atraeアドベントカレンダー21日目を新卒一年目の櫻井が担当します！！！

僕は入社から半年間は組織改善プラットフォーム「wevox」(ウィーボックス)のバックエンド(rails)とフロントエンド(react/typescript)の開発を担当していました。

半年で異動となり、現在は転職サイトGreenでバックエンドとSRE(駆けだし)を担当しています。

# 新卒エンジニア研修を新卒エンジニアが作る

アトラエには今年4人の新卒エンジニアが入社しました。いずれのメンバーも開発経験はあまりなく、ほぼ未経験で入社です。

そのため、今年は新卒エンジニア研修と称して、先輩エンジニア方から開発のイロハを教えていただいてました。

唯一の情報系出身の僕は知識として学んでいたことはあったのですが、実際に開発している中で話を聞くと実感値といいますか、血肉となる感じがして改めて楽しく学べていました。

半年ほど、たったくらいからそもそもこの新人研修。先輩に用意してもらわなくても、どういう事を学ぶべかだけ聞き、自分たちで勉強し、教えた方が社内のリソースや自分たちの理解度を高める事を考えると良いのではと思い、今では自分たちで教えあっています。


その中で自分はDB設計周りを担当することになり、DBにまつわる書籍やネットの記事を調べまくりました。
そこで一番問題となったカテゴリがあります。それが**正規化**です。

データベース設計やテーブルを考える上で大変基礎的なものであるにも関わらず、初めて学ぶ人にとってはとても理解のしづらい分野だと思います。

にも関わらず、各書籍や記事により、微妙にニュアンスが違っています。
慣れてしまえば、理解できるとは思うのですが、、、(学生時代にもなんとなくでテストを乗り切ってしまった。)

そんな僕たちを苦しめる正規化とはなんなのかというものを改めて、まとめてしまい、正規化に苦しむこれからの方がこの記事さえ読めば理解できるようになればと思い、書こうと思いました。

# 改めて、正規化とはなんのためにするのか

前置きが大変長くなり、お待たせしました。お待たせし過ぎたかもしれません。

そもそも、正規化とは何の為にするのか。改めておさらいしておきましょう。

## データベースに必要な要件
データベースに求められる必要な要件とは以下の4つであると言われています。

- 共有利用
    - 複数ユーザーからの共有利用
- 一元管理
    - One Fact in One Place (一つの事実は一つの場所にあるべきというDBに置ける重要な考え方)
- 信頼性
    - 耐障害性や高度なセキュリティ
- 性能
    - 処理速度やSQLの検索のパフォーマンス

このうち、**共有利用および信頼性**はDBMS(出たベースマネジメントシステム)による依存度が大きいと言われています。(MySQLやPostgreSQLのことを指します。)

したがって、データベースを設計する上で設計者が特に重要視すべきことは**一元管理と性能**なのです。

この一元管理をする為に重要な作業があります。それが**正規化**です。

## 正規化とは
正規化というものが何なのか改めて言語化しますと、
#### １つのデータが複数のテーブルに存在すること(冗長性)を排除し、更新時の不都合/不整合を防ぐ。

です。

テーブル内の従属性を見抜き、第3正規形にまで正規化することをいいます。

この背景を踏まえた上でテーブルを正規化していきましょう。

今回は果物の商品入荷についてのテーブルを用意し、それらを元に行なっていきたいと思います。
元となる非正規形テーブルはこちらです。
<img width="1171" alt="非正規系.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243735/b270a22f-eb0a-4259-efd4-362fb22f4377.png">


### 非正規形→第一正規形
第一正規化をすることは2つです。

#### 属性の繰り返しを排除

#### 一つのセルに一つの値

上記のテーブルのままでは属性の繰り返しはありませんが、一つのセルに複数の値が入ってしまっている部分があります。それらを解消しましょう。
第一正規化が終わった図が下図になります。

<img width="1171" alt="第一正規形.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243735/2e8e6282-3af6-f2ec-21bf-16c1bd4d5981.png">


### 第一正規形→第二正規形

第二正規化で行うことは

#### 部分関数従属を解消し、完全従属関数を実現する為にテーブルを分離させる
です。

**部分関数従属というのはレコードが一意であると定める要素の一部で判断できる要素です。**

レコードが一意であると定める要素というのはテーブルにおける主キーのことを指します。

先ほどのテーブルに置いて、例えば**住所**という属性は**仕入先**がわかってしまえば、必ずわかります。

このテーブルのレコードが一意であると判断するには**仕入先・商品・入荷日**の3つが必要となります。
したがって、**仕入先**のみでわかってしまう住所という属性があるこのテーブルは部分従属関数のあるテーブルなのです。

**完全従属関数というのはレコードが一意であると定める要素の全てが揃わないと判断できない要素です。**

今回でいうと、入荷数という属性は商品・仕入先・入荷日の3つが揃って初めて分かります。このような属性のみで構成されるテーブルが完全従属関数を満たすテーブルなのです。

難しい言葉を並べましたが、まとめると

**主キー**によって残りの属性の値が特定される属性のみのテーブル構成にするというのが第二正規化で行うことです。

以下は第二正規化を行なったテーブルです。
#### 入荷テーブル
<img width="521" alt="商品正規化前テーブル.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243735/3427a165-bd08-e5d6-13a0-5f9bd4e4a81d.png">

元のテーブルが↑です。主キーは**商品名・仕入先・入荷日**です。

#### 仕入先テーブル
<img width="521" alt="仕入先正規化前テーブル.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243735/603538a6-4317-0b98-1c08-4affa8f68b87.png">
主キーは**仕入先**です。

#### 商品テーブル
<img width="391" alt="商品テーブル.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243735/42d220bc-ab3f-e75c-8653-f9262fc72559.png">
主キーは**商品**です。



### 第二正規形→第三正規形
第三正規化で行うことは
#### 推移関数従属を解消する
です。

#### 推移関数従属とはレコードを一意に判断できる要素ではない要素から従属している要素です。

先ほどは主キーが分かれば分かる属性でしたが、今度は主キーではない属性から別の属性を導けるものを分解します。
今回でいうと、代表者名と代表者連絡先の関係性をあげることができそうです。
<img width="391" alt="仕入先テーブル.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243735/8066ee0a-1d8b-1eed-ae3e-c0cbb8dd8627.png">
<img width="261" alt="代表者名テーブル.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243735/8d1c2bfe-6479-91fe-a4ae-5a73f2e062de.png">

したがって、その部分を分離し、新たなテーブルを作ることで推移関数従属を解消します。

これによって正規化は完了となります。

<img width="976" alt="スクリーンショット 2019-12-22 1.40.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243735/b142c9f9-1805-e14b-750d-00fd4dd11685.png">


いかがでしたでしょうか？
かなり基礎的な内容だったとは思いますが、意外と中身を掴むまでは苦労するところかと思います。

以上、アトラエアドベントカレンダー21日目でした！

明日は、アドベントカレンダーをやろうと発起人の三上くんの記事です！お楽しみに！