データベース（RDB）設計の進め方！

#はじめに
RDBMSのデータベース設計（論理）の進め方について、設計をする際、こんなことを考えながら進めているなというのを出来るだけ分かり易く記載したいと思います。ただDB設計には「これが正解」というものはあまりなく、要件の必要条件を満たしているDB設計が正解となります。とは言え、考慮した方が良い点や注意点などはありますので、何から始めたら良いの？という方の参考になれば幸いです。

※論理設計の話しなのでカラムの型やサイズ、パフォーマンス（INDEX（索引））などは割愛しますが、実際にDB設計をする際は、使用するDBの型・キー・制約の種類は事前にインプットを入れておいた方が良いです。

#DB設計におけるポイント
先にDB設計を行う上で重要だと思うポイントをあげます。

* 要件・仕様を理解しているか（要件を満たすテーブル／カラムが揃えられるか）
* 要件にない（見えにくい）システムの仕様を想像できるか
* レコードを一意に識別できるキーが存在するか
* 必要な正規化がなされているか
* 将来性を考えられるか

##（余談）テーブルのイメージが湧かない場合
DB設計したいけど、そもそもDBのテーブルって何？という場合はエクセルの表を思い浮かべてもらうと分かり易いと思います。テーブルとは下記のような表をDBの中に作るイメージです。そして、表を複数作り、テーブル同しつながりを持たせたDBをRDB（Relational Database）ぐらいでイメージすると理解しやすいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270976/16b9b2f6-d0e3-e643-7027-ee62be8da603.png)

##1．情報を整理しテーブル・カラムの洗い出しを行う
DB設計を進める上でなくてはならないものとして「各仕様書」があります。
**要件・仕様を理解**していなければ、そもそも必要な**テーブルの種類**や**カラムの定義**が行えませんので、まずはどんな要件のどんなシステムを構築するのかちゃんと理解しましょう。
そのうえで、要件定義書や外部設計書などをもとに情報を整理しテーブルとカラムの洗い出しを行います。

###1-1．テーブルを洗い出す
今回はサンプルとして簡易なECサイトのテーブル定義を行う想定で進めます。要件は会員が登録でき、商品はカテゴリで分類され、注文できるというシンプルなものにします。（本来は在庫や出荷、決済など多くのテーブルが必要になりますが割愛します）


まずは仕様書を確認しながらテーブルをどんどん洗い出していきます。テーブルはあとで全体を見ながら調整するため、ここは当てでも良いので悩み過ぎずに一旦書き出していきましょう。※慣れてきたら次の1-2も同時に行うとスムーズです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270976/71524f59-09bd-71da-73d5-a181db95d959.png)

###1-2．カラムを洗い出す
更に仕様書や外部設計書を確認しながらテーブルにカラムを肉付けしていきます。
またテーブルの**レコードを一意に識別する主キー**を決めていきます。レコードを一意にするキーが必要な理由は、データの更新や削除を行う際、**対象レコードを1つに決めることが出来きる**ようにするためです。
そのため、作ったテーブルに対しINSERTやUPDATE、DELETEといった操作が、**SQLで望んだ結果で実行出来そうか**という観点で確認することでミスや漏れが減らせます。

RDBでは下記のように、注文テーブルの中に購入した商品や会員の情報を冗長的に持たせるのではなく、商品テーブルや会員テーブルの主キー（商品ID,会員ID）を持たせることで、テーブルどうしをSQLで繋ぐことが出来るため、注文テーブルに商品や会員の情報を持たせる必要がありません。また商品の名称や価格が変更になった場合でも、注文テーブルでは商品IDのみ保持しているため、商品テーブルの情報を更新すればよいということになります。（この表のような形式（リレーショナルモデル）に基づいたデータベースであるため、リレーショナルという名前が付き、項目どうしを関連付け扱うことができます）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270976/4f918b19-0435-86e9-8faa-732109fc5b59.png)
徐々にテーブルらしくなってきました。

#2．要件にない（見えにくい）システムの仕様を想像できるか
次に要件としては、商品があり、注文があり、会員がいるので揃っていますが、例えば、既に注文された（注文テーブルに入っている）商品を物理削除しても大丈夫なのか？（※1）や、いつ、誰が登録したデータなのか分からなくて大丈夫なのか？など**データの整合性**や**後々必要になりそうな項目を想像し検討する**必要があります。

（※1）外部キーの詳しい説明は割愛しますが、外部キーを貼ることでテーブル間に親子（依存）関係が出来るため誤った削除を防止することが出来ます。但しデータ操作上エラーになるだけですので、エラーチェックはアプリケーション側で作る必要があります。

そこで、物理削除されては困るテーブルには、例えば論理削除フラグを設け、商品IDと論理削除フラグ(0,1)で主キーとする、また登録日、登録者などの項目を持たせることで、いつ誰が操作したレコードなのか後から追えるようにするなど、**仕様書から見えにくい箇所**も考えながらテーブル設計を進めます。（本来は登録者なども管理者テーブルを作成しIDを紐づけます）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270976/ee8ceed7-2583-2bc4-42af-cf0212196949.png)

#3．正規化を考える
例えば、商品データに紐づくカテゴリは下記のようなデータが登録されるとします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270976/a2e64c32-64bc-a4b3-03b8-e8c638dd486c.png)
カテゴリの列に注目すると「家電」というカテゴリ名が**重複**していることに気づきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270976/f8a665dc-2913-369c-735c-a7b8459c858d.png)
そこで、例えばカテゴリIDというキーを持たせた場合（実際は付ける必要はありませんが説明し易くするため）、「商品ID」に関わらず「カテゴリID」のみで「カテゴリ」を一意（C001なら家電、C002なら家具）に決めることが出来ます。
このようなカラムを切り離し、別のテーブルとして作り、データを利用しやすくすることを正規化（段階により第一正規形、第二正規形、第三正規形などが存在）と呼びます。

要件にもよりますが、基本的にはマスタデータとして再利用されやすいデータを別テーブルとして切り離します。例えば「価格」も金額が重複することはありますが、1円でも異なる度に価格テーブルにデータを入れ、商品テーブルと紐づけるのは運用が煩雑になるため、このケースでは別テーブルに切り出しません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270976/49b7e517-8700-e861-a065-1207283dd259.png)

正規化を行うメリットとして「家電」を「家電製品」に変更したい場合、非正規化のままレコードの更新を実行すると「家電」と登録されている商品テーブルのレコードすべてが更新されることになりますが、別のテーブルに切り出すことで、カテゴリテーブルの「家電」レコード1行を更新すれば良いことになるため更新時の負荷が下がります。
また、商品テーブルからカテゴリを外に出すことにより、商品が存在しなくとも事前にカテゴリのみを登録する作業が行えます。

- データ更新時の負荷が下がる
- データを冗長的に持たないことでマスタデータの管理が容易になりメンテ性があがる
- データの不整合を防ぐ
- マスタデータの使い回しなど拡張性があがる

＜余談＞
基本的に正規化は実施した方が良いですが、データの更新や削除が行われない、他のテーブルの登録、更新、削除によってデータの影響を受けない、検索でしか使われないカラムなどは、冗長的にデータを保持した方が、複雑なSQLを組まない分パフォーマンスが良いケースがあります。その場合は正規化をせず、冗長的にカラムを持つケースがあります。

#4．将来性を考える
これはやり過ぎる必要はないですが、ある程度業界知識がある場合は、テーブルを設計している際に要件の抜け漏れが見えてくることもあるため、**設計側の立場から提言や助言を行う**ことで後々不要な再設計を防止することが出来ます。
例えば、サンプルの設計では商品にカテゴリが1つしか紐づけることが出来ませんが、今後、同じ商品に複数のカテゴリを紐づけたいとなる可能性は十分考えられます。その場合は、下記のように中間テーブルを作成します。あわせて注文テーブルも複数別の商品が購入できるように設計を変えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270976/8727d709-d374-6c02-bcfe-7544c1f700d4.png)

#おわりに
データベース設計は最初から完成形を作ろうと時間をかけ悩むのではなく、テーブルの洗い出しやカラムの持ち方など、一旦当てで作り始め、作りながら全体を俯瞰しつつ、追加／修正を繰り返すことで完成形に近づけることが出来ると思います。

また、一気に全部を作ることをイメージするのではなく「商品とカテゴリの関係性のテーブル」を作る、次に「商品と注文の関係性のテーブル」を作るなど、小さい単位でグループ化するように作り、最終的に全体と繋げるように考えると業務要件の大きな設計も、簡易な要件の設計も変わらず設計することが出来るかなと思います。

全体を俯瞰すると言えば、ER図について触れていませんでしたが、説明の中で登場していた表と表を線で結んだような、視覚的につながりをあらわす表をER図と呼び、全体を把握するのにとても役に立ちます。（今回は簡易的に記載していますが、ER図だけでデータの繋がりが、1対1、1対多、多対多、であるということも表現できます）

データベース設計が出来るようになると、システム開発の幅が広がると同時に、システムの肝を押さえることが出来るので、より開発が楽しくなりますね！

参考になれば幸いです。