データベース設計入門を学んでみる

### はじめに
エンジニア歴5年ほどの私ですが、そういえばコードの書き方しか勉強してこなかったなと思い設計周りの勉強を始めました
まず初めにアプリの基となるデータベースがどのように設計されているのかを見てみたくて下記のUdemyのコースを受講しました
今回は受講した際のメモを記していきます

https://www.udemy.com/course/think-data-structure/

### 注意
本記事はメモをAIに添削を依頼し、さらにそれっぽく改訂していますので読みにくい部分があるかと思いますがご了承ください

### データベース設計入門
世に蔓延るアプリケーションはDBの内容を表現しています
アプリ設計の最初にDB設計をするらしいです

`リレーショナルデータベース`という物が有名だが、これは要は表同士をくっつけて一つの集合体にすることです

#### リレーショナルデータベース
`リレーショナルデータベース`は、異なる表に格納されたデータを関連づけることで、情報を一つの集合体として表現する方法で、各表は特定のデータの集合（例えば、顧客、製品、注文など）を表し、これらの表間の関連性は`リレーションシップ`と呼ばれています
リレーショナルデータベースの主な利点は、データの重複を減らし、生合成を保つことができるという点です

##### 表を使って説明
具体例として「users」テーブルと、「posts」テーブルの例を使って、X（旧Twitter）において誰がどんなポスト（旧ツイート）をしているかを取得します

##### usersテーブル
| id(外部キー) | name |
|:-----------|------------:|
| 1       | ユーザーA        |
| 2     | ユーザーB      |
| 3       | ユーザーC        |

##### postsテーブル
| user_id(外部キー) | content |
|:-----------|------------:|
| 1       | ツイート1        |
| 2     | ツイート2      |
| 3       | ツイート3        |

「users」テーブルの「id」「posts」テーブルの「user_id」と対応する
これにより、特定のユーザーが投稿したすべてのポストを効率的に取得することが可能になります
例えば、ユーザーA（id=1）が投稿したポストを取得するには、「posts」テーブルで「user_id」が1の行を全て抽出することで取得できるようになります

この場合、「posts」テーブルにはユーザーの詳細を直接保存する代わりに、「users」テーブルへのリンク（つまり、ユーザーID）を保存します。これにより、ユーザーの詳細は「users」テーブルで管理され、情報が変更された場合もその箇所を更新すれば良いことになります

例えば、ユーザーAがメールアドレスを変更した場合、ユーザーAが投稿した全てのツイートでメールアドレスを更新する必要はなく、「users」テーブルの該当行だけを更新すれば良いです。これが`正規化`の一例であり、データの重複を排除し、データの整合性を保つことでデータベースの保守性を高めるための重要な手法です


#### リレーショナルデータベースのメリット
- 汎用性：リレーショナルデータベースは幅広いアプリケーションで利用できます
- 利用企業が多い：多くの企業がリレーショナルデータベースを利用しており、その結果、需要が高まっています
- 構造が固定されている：リレーショナルデータベースは定義されたスキーマに基づいてデータを保存します
これはNoSql（キー、バリュー型）とは対照的で、これによりデータの整合性が保たれます

#### リレーショナルデータベースのデメリット
- 重くなることもある：リレーションシップの多いデータベースは余計なデータの呼び出しによりパフォーマンスを低下させる可能性があります　これはエンジニアのスキルに依存します
- 利用企業が多い：多くの企業がリレーショナルデータベースを使用しているため、その使用が当然と思われてしまいます
-  設計に依存してしまう：テーブル構造が不適切だと全体のアプリケーションのパフォーマンスに影響を与える可能性があります

### リレーショナルデータベースの種類
1. **MariaDB**：MySQLの上位互換であるMariaDBは、MySQLの機能に加えて新たな機能が搭載されています。大規模な設計が可能で、ビッグデータなどに対応し、マルチサーバーによりスケーリングが可能で本番環境に強いです。また、LinuxOSではデフォルトで使用されるデータベースです
2. **PostgreSQL**：ビジネス向けのリレーショナルデータベースです。超大規模な設計に対応し、拡張性が高く、将来的に必要とされる機能を追加することが可能です。NoSQLをサポートしているため、key-valueストア形式も使用できます
3. **OracleDB**：伝統的な商用データベースであり、最低42,000円で使用が可能です。大規模な設計に対応し、サポートが充実しています。また、計算結果だけをまとめた仮想列機能など、豊富な機能を有しています
4. **AWS Aurora**：クラウド時代のリレーショナルデータベースで、MySQLの5倍、PostgreSQLの3倍の速度を持ちます。MySQL、MariaDB、PostgreSQLとの互換性が高く、開発やステージング環境にこれらを使用し、本番環境にはAuroraを使用することができます。さらに、AWSの安心感があり、バックアップや復帰などのトラブルを自動で解決します

### SQLにおける3つのJOIN
SQLにおけるJOINは、異なるテーブル間で関連性を持つデータを取得するための重要な操作です。1対1、1対多、多対多のリレーションは、以下のように理解できます。

1. 1対1（1：1）: このタイプのリレーションは最もシンプルな形で、一つのレコードが他のテーブルの一つのレコードに直接対応しています。例えば、「users」テーブルと「tweets」テーブルをJOINすることで、誰がどんなツイートをしたかを把握できます
2. 1対多（1：多）: このタイプは一つのレコードが他のテーブルの複数のレコードに対応しています。例えば、「いいね」機能では、一つのツイートに対して、複数のユーザーが「いいね」を押すことができます。つまり、「tweets」テーブルに対して、「users」テーブルの複数のレコードが対応します
3. 多対多（多：多）: このタイプは複数のレコードが他のテーブルの複数のレコードに対応しています。これは一般的に中間テーブルを用いて実現されます。例えば、ブログとタグの関係では、一つのブログに複数のタグがつけられ、一つのタグは複数のブログに対応します

### 利用例：シンプルメモアプリのデータベース構造
機能としては、ユーザーがタグ付きメモを残す程度のものです
Usersテーブル（ユーザーが退会した際に参照できないようにするため、物理削除）

| id | integer | [pk, increment] |  |
| --- | --- | --- | --- |
| email | string | [unique, not null] |  |
| password | string | not null |  |
| name | string | not null |  |
| created_at | timestamp |  | 作成日時 |
| updated_at | timestamp |  | 更新日時 |

## memosテーブル（メモの内容を復元したいときのために論理削除 deleted_at=null）

| id | integer | [pk, increment] |  |
| --- | --- | --- | --- |
| user_id | integer | [not null] | 外部キー：users.id |
| content | string | not null |  |
| deleted_at | timestamp | not null |  |
| created_at | timestamp |  | 作成日時 |
| updated_at | timestamp |  | 更新日時 |

## tagsテーブル（タグ情報に復元は無いので物理削除）

| id | integer | [pk, increment] |  |
| --- | --- | --- | --- |
| user_id | integer | [not null] |  |
| name | string | not null |  |
| created_at | timestamp |  | 作成日時 |
|  |  |  |  |

memosとtagsで1対多のリレーションを行うとメモに1つのタグしかできないようになるので
複数のタグを複数のメモを付与できるようにするため、多対多のリレーションをする必要があります
そのためには中間テーブルを作成します

## memo_tags（中間テーブル）
| memo_id | integer | [not null] | 外部キー:memos.id |
| --- | --- | --- | --- |
| tag_id | integer | [not null] | 外部キー:tags.id |

以上でシンプルメモアプリのデータベース設計を完了とします

### 最後に
本記事は基礎的な部分ですが、改めてデータベースの設計部分を学んで業務でなんとなく使っていたテーブルとリレーションの意味を把握しやすくなった気がしました
また、リレーションに関しては余計なリレーションを外すだけで爆発的に軽くなったこともあるので今一度、テーブルのリレーション周りをなんとなく見直してみるのも良いかもですね