[データベース] 初めて設計する際に学んだこと（超入門）

# はじめに
駆け出しエンジニアの私が、初めて "データベース" というものに触れてみて、学んだことを共有したいと思います。
初めてデータベースを設計する際に少しでも参考になれば幸いです。


# そもそもデータベースって何？
データベースは、例えるなら、たくさんの情報を整理してしまっておく「大きな図書館」のようなものです。たとえば、私たちは図書館で本を探すときに、タイトルや作者の名前を使ってすぐ見つけることができます。
それと同じように、データベースは、コンピュータの中にあるたくさんの情報（たとえば名前や住所、電話番号や商品リストなど）を、簡単に探したり使ったりできるようにまとめておく場所です。



## なぜデータベースが必要なのか
データベースがない頃、人々は情報を管理するために「紙」を使っていました。ノートや帳簿などに手書きで記録して、それを整理していましたが、データベースを使うことで改善されることが多くあります。

#### 1.より多くの情報を整理できるようになる
紙を使って管理すると、情報が増えるたびに新しいノートや帳簿を用意しなければいけませんでした。そして、それをきれいに整理するのにも多くの時間と労力がかかりました。しかし、データベースなら、コンピュータの中に情報を保存するので、物理的なスペースを気にせず、どれだけ多くの情報でも効率的に管理できます。また、分類や整理も自動化できるので、大量の情報を扱うのがとても簡単になります。


#### 2. 情報をすぐに探せるようになる
紙の場合、必要な情報を探すためにページをめくったり、カードを1枚ずつ確認したりする必要がありました。しかし、データベースなら、キーワードや番号を入力するだけで、欲しい情報がすぐに見つかります。たとえば、学校の名簿で「佐藤」という名前の生徒を探すときも、データベースなら一瞬で検索できます。これにより、時間の節約にもつながります。


#### 3. 情報の共有が簡単になる
紙の場合、複数の人が同時に同じ情報を見ることは難しく、一部の人だけが情報を持っていることもありました。しかし、データベースを使えば、インターネットやネットワークを通じて、複数の人が同時に情報を閲覧したり編集したりできます。たとえば、大きな会社では、社員全員が商品や在庫のデータを確認することができるので、仕事がスムーズに進むようになります。


#### 4. 情報が失われにくくなる
紙の場合、紛失や汚れ、破損などで情報が失われることがありました。しかし、データベースでは、情報をバックアップ（予備の保存）したり、セキュリティを強化したりすることで、大事なデータを守ることができます。これにより、災害や事故が起きても情報を簡単に復元できるようになります。


#### 5. 人為的なミスを減らせる
紙の記録では、書き間違いや計算ミスが起きることがよくありました。しかし、データベースは、入力された情報を自動的にチェックしたり、計算を正確に行ったりするので、人間のミスを減らすことができます。これにより、トラブルや間違いを防ぐことができます。

<br>
これらの理由から、現在は多くの場面でデータベースが使われています。




## データベースはこんな場面で使われています
- 「学校の出席管理や成績管理」
学校では、生徒の名前、出席状況、成績などをデータベースで管理しています。これにより、先生が簡単に出席簿を確認したり、保護者に成績を共有したりすることができます。


- 「図書館の本の貸し出し管理」
図書館では、借りられている本やその返却期限をデータベースで管理しています。利用者の名前や貸し出し記録をすぐに検索できるため、本の紛失や管理ミスを減らすことができます。

- 「病院や診療所の患者データ管理」
病院では、患者の診療記録、処方箋、検査結果などをデータベースで管理しています。これにより、医師は患者の病歴をすぐに確認でき、的確な診断や治療が可能になります。

- 「オンラインショッピングの在庫管理」
Amazonや楽天のようなオンラインショップでは、商品の在庫や価格、注文情報をデータベースで管理しています。これにより、利用者は在庫の有無を確認できたり、注文履歴を簡単に追跡したりできます。

- 「銀行の取引記録管理」
銀行では、口座の残高、取引記録、振り込み履歴などをデータベースで管理しています。これにより、顧客はいつでも口座情報を確認でき、銀行の窓口やATMでもスムーズに取引を行えます。

- 「スマホの連絡先や写真の保存」
スマートフォンの中では、電話番号やメールアドレス、写真などがデータベースの仕組みを使って管理されています。このおかげで、必要な情報をすぐに検索したり、データをクラウドにバックアップしたりできます。

- 「交通機関の運行情報管理」
電車や飛行機の予約システムでは、座席の空き状況や運行スケジュールをデータベースで管理しています。これにより、利用者はいつでも空席を確認して予約ができるようになっています。

- 「ソーシャルメディアのユーザーデータ管理」
FacebookやInstagram、LINEなどでは、ユーザーの名前、投稿、メッセージなどをデータベースで管理しています。この仕組みによって、世界中の人々とつながることが可能になっています。

- 「気象データの記録と予報」
気象庁や天気予報サービスは、気温や降水量、風速などのデータをデータベースに保存して解析しています。これにより、正確な天気予報や災害情報を迅速に提供できるのです。

- 「ゲームのプレイヤーデータ管理」
オンラインゲームでは、プレイヤーのキャラクター情報、スコア、持ち物などがデータベースで管理されています。この仕組みにより、どこからログインしても同じデータで遊ぶことができるのです。



# データベースを設計する
データベースを設計するうえで欠かせないものに、「ER図」と呼ばれるものがあります。
ER図（Entity-Relationship Diagram）は、データベースを設計するときに使う図のことで、「データの構造」や「データ同士の関係」を分かりやすく表したものです。
ER図は、データベースを作る前に何をどう整理するかを考えるための設計図のような役割を持っています。

おすすめのER図作成サイト（dbdiagram）
https://dbdiagram.io/d


#### ER図の基本要素
ER図は、主に3つの要素で構成されています：
1. エンティティ（Entity：実体）
保存したい情報の「モノ」や「コト」を指します。
例：学校なら「生徒」「先生」「クラス」など。
2. リレーションシップ（Relationship：関係）
エンティティ間の関係性を表したものです。
例：「1対1」「1対多」「多対多」など。
3. アトリビュート（Attribute：属性）
エンティティやリレーションシップが持つ具体的な情報（特徴）を表します。
例：生徒の場合、「名前」「学年」「出席番号」など。



#### リレーションの種類
リレーションには主に以下の3種類があります：
- 1対1（1:1）
1つのエンティティが他のエンティティの1つのインスタンスに対応する場合。
例: 「社員」と「社員証」の関係。
![スクリーンショット 2024-11-27 19.20.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899248/9cbc0d97-6e8e-6cd1-5a2a-38742a2bf968.png)
※1対1の関係を実現するため、外部キーにユニーク制約を加えることが重要

- 1対多（1:N）
1つのエンティティが他のエンティティの複数のインスタンスに対応する場合。
例: 「顧客」と「注文」の関係（1人の顧客が複数の注文をする）。
![スクリーンショット 2024-11-27 19.31.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899248/9214c3e9-7d62-f039-0be3-057e7126f28e.png)
※外部キーはユニークである必要がなく、1つのレコードが複数の関連付けを持つことを許容します

- 多対多（M:N）
1つのエンティティが他のエンティティの複数のインスタンスに対応し、逆もまた同様の場合。
例: 「学生」と「コース」の関係（1人の学生が複数のコースを受講し、1つのコースに複数の学生が参加する）。
![スクリーンショット 2024-11-27 19.35.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899248/6998218d-51b3-5831-2a21-ef70fe99543d.png)



#### リレーションに関わるキー
- 主キー（Primary Key）
各エンティティの一意性を保証するために使用される。
例: 顧客テーブルでは「顧客ID」。
- 外部キー（Foreign Key）
エンティティ間の関係を作るために使われる。
例: 注文テーブルでは「顧客ID」を外部キーとして使い、顧客テーブルと関連付ける。



#### 多対多（M:N）の解決方法
多対多のリレーションはそのままでは実装が難しいため、「中間テーブル（ブリッジテーブル）」を用いて1対多の関係に分解します。
- 例: 学生（Student）とコース（Course）の関係。
1.中間テーブル「受講（Enrollment）」を作る。
2.学生テーブルと受講テーブルは1:Nの関係。
3.コーステーブルと受講テーブルも1:Nの関係。



#### エンティティとテーブルの違いとは

- 主な違い

項目|エンティティ|テーブル
-|-|-
定義段階|抽象的な概念（設計段階で定義）|具体的な実装（データベース内の構造）
役割|管理する対象の「モデル」|データを保存する「容器」
属性|属性を持つが、実装はされていない|属性はカラムとして実装される
対応関係|1つのエンティティは1つ以上のテーブルになる場合もある|1つのテーブルが1つのエンティティに対応する


- 具体例
エンティティ: 「社員」
属性: 「社員ID」「名前」「部署」
テーブル:
「社員」テーブル → カラム: 「社員ID」「名前」「部署」




# 実際につくってみる
今回は、簡易的な「イベントの予約管理アプリ」をつくるためのデータベースを、設計していきたいと思います。

下のイメージのような予約フォームに記入すると、

![スクリーンショット 2024-11-28 10.57.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899248/037db5d7-e52c-6ecb-5e30-db0b74a89d81.png)

下のようなメッセージが登録されたメールアドレスに届くようにしたいです。

![スクリーンショット 2024-11-28 11.01.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899248/a5281c76-1f0d-959b-b6c4-0c459c158e81.png)


では、どのようなデータベースを設計すれば良いでしょうか。

#### 1. イベントの抽出
まずはデータベースを使用するきっかけとなった出来事（イベント）を探し出します。
今回の例でいうと、「予約する」というイベントが発生しています。
"〜する"と動詞で言えるものを探すと見つけやすいです。


#### 2. エンティティの作成
イベントが抽出できたら、いよいよエンティティを作成しています。
ここでのポイントは、5W1Hを意識することです。
今回の例では、「誰が」「何を」（予約する）というようになるので、

（誰が）＝　「user」
（何を）＝　「event」

と二つのエンティティが必要なことがわかりました。
ここで、「user」は「◯◯イベント」全体に申し込むわけではなく、特定の枠（日時）に予約をするので、「event」エンティティの名前を「event_slot」に修正します。

「user」「event_slot」

次に、それぞれのイベントがどのようなアトリビュートを持つべきかを考えます。
ここでは、実際の予約フォームを参考にするとわかりやすいです。
- 「user」には
姓
名
セイ
メイ
メールアドレス
来場日
来場時間

- 「event_slot」には
開催日時

を持たせることにします。
ここまでをER図にまとめると以下のようになります。
![スクリーンショット 2024-11-28 12.08.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899248/4b91e457-8c55-f39a-71cc-560af28e36eb.png)


#### 3. リレーションの設定
エンティティが作成できたら、エンティティ間のリレーションを設定します。
1人のuserが複数の枠を予約できる場合、1つの予約枠にも複数のuserが参加するので
リレーションは　多対多（M:N）となります。-> 中間テーブルを作成して、、、
しかし、今回の例ではもっとシンプルに設計することができます。
- 一度きりのイベントの予約を管理したいだけなので、わざわざ一人一人のユーザー情報を取得して管理する必要はない。
- ユーザー情報のエンティティに特定の日時が保存されるのは違和感
- イベントに複数の枠を予約するユーザーも少ない


以上の理由から、
「user」エンティティの名前を「entry（応募）」に修正します。
すると、1つのentry（応募）で予約できる枠は1つ、1つの予約枠には複数のentryがあるので
リレーションは　1対多（1:N）となります。
また、「entry」の　「来場日と来場時間」を「event_slot」の「開催日時」とリンクさせます。
そうして完成したER図が以下のようになります。

![スクリーンショット 2024-11-28 12.47.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899248/c039f83c-ae7d-8292-41ac-98226044912e.png)


ここまで設計できたら、あとは実際にデータベースへアクセスするときのことを考えながら、自分のプロダクトに合わせて更に修正を加えていきます。
- 可逆性を持たせる
- 数学的正規化と業務的正規化
- one fact in one place
- インデックスの設計
- トランザクションも考える
- トラフィック増加によるパフォーマンス劣化を減らす
- ストアドプロシージャ（sql内部に保存する、自作の関数のようなもの）を作成する

などなど、データベース設計はとても奥が深いです。
（発展的な内容なので割愛します。「楽々erdレッスン」という書籍がオススメです。）




# おわりに
初めてデータベースを設計してみましたが、実際につかってみて反省することが多々ありました。
（ユーザーのフルネームを何度も使用したい場合、毎回「姓」と「名」をつなげる処理をするのは面倒なので、"フルネーム"というアトリビュートを最初から持たせておきたい、など）
->　その場合「姓」や「名」が変更される度に「フルネーム」も合わせて変更させる必要があります。

#### ①設計する -> ②実際につかってみる -> ③改善する


実際につかってみないと、設計の段階では気づけなかった不便さに気づくことができません。
たくさん設計して、使って、データベースに慣れていきましょう！