【DB設計】外部スキーマ・概念スキーマ・内部スキーマについてまとめてみた

## はじめに
今回の記事は、DB(データベース)設計における「3層スキーマ」の概念についてまとめました。
システムの柔軟性とメンテナンス性を向上させるためにこちらの概念は非常に重要になってきます。

## 3層スキーマとは？
DBの設計上の概念として以下の三つの概念が存在します。
- *外部スキーマ(ビュー層)*
- *概念スキーマ(論理層)*
- *内部スキーマ(物理層)*

これらを合わせて3層スキーマと呼びます。
現代の多くのDBシステムで採用されており、リアルタイムで変化するデータバンクを適切に操作し、情報を抽出する効果的な手段となっています。

「**スキーマ**」とはデータベースの設計図のようなもので、データの格納場所を定義するために設定されます。

### *外部スキーマ (ビュー層)*
外部スキーマとは、ユーザーが最終的に使うためのデータ構造のことを指し、**DBからのデータの見え方**を決定するレイヤーです。
このレイヤーでは、ユーザーまたはアプリケーションごとに独立したビューを許可し、ユーザーが必要とするデータだけにアクセスできるように、データのフィルタリングを行います。

また、**データの隠蔽**も行います。全てのデータが全てのユーザーに必ずしも関連性を持たない場合や、特定の情報を特定のユーザーから隠す必要がある場合に利用できます。

:::note warn
SQLの世界でいう「ビュー」はユーザーが見やすいようにDBから抽出したデータを指します。データの見え方をDBレベルで定義していることを忘れないでください。
:::
例えば、このように
| 注文ID | 注文日     | 顧客ID | 顧客名               | 住所         | メールアドレス         | 商品ID | 商品名           | 個数 |
|--------|------------|--------|----------------------|--------------|------------------------|--------|------------------|------|
| 1001   | 2024-10-05 | 001    | プロスイマー佐藤     | 東京都***     | satou@gmail.com        | P001   | 水着    | 1    |
| 1002   | 2024-10-15 | 002    | ゴールデンエイジ岡本 | 大阪府***      | okamoto@gmail.com      | P002   | 枕 | 2    |
| 1003   | 2024-10-20 | 003    | プロボーラー田中     | 北海道***     | tanaka@gmail.com       | P003   | カメラ     | 1    |
| 1004   | 2024-10-25 | 004    | バックエンド鈴木 | 京都***      | suzuki@gmail.com       | P004   | ゴルフクラブ      | 3    |
| 1005   | 2024-10-25 | 005    | テニスプレイヤー橋本 | 東京都***      | hashimoto@gmail.com       | P005   | 水着      | 1    |

受注テーブル、顧客テーブル、商品テーブルなどを結合して、「**見せるために加工したデータ（ユーザーが最終的に使うためのデータ）**」構造にすることを外部スキーマと言います。

### *概念スキーマ（論理層）*
概念スキーマは、データ間の関係性やデータの種類を定義する、**DBの論理的な構造**を示すレイヤーです。簡潔に言うと、外部スキーマをDB上で扱いやすくするために重複の排除や項目の分割などを行ったものになります。
一般的には、DB内の全てのデータを包括します。データのうちどれが互いに関連しているのか、どれが一緒に分類されるべきなのかを定義します。そしてデータの規則と制約を設けます。
概念スキーマがあることで、データの不整合性を防ぎ、同時にデータの整合性を維持しています。

先ほどの例の外部スキーマを一つのテーブルとして持っていたと考えましょう。
| 注文ID | 注文日     | 顧客ID | 顧客名               | 住所         | メールアドレス         | 商品ID | 商品名           | 個数 |
|--------|------------|--------|----------------------|--------------|------------------------|--------|------------------|------|
| 1001   | 2024-10-05 | 001    | プロスイマー佐藤     | 東京都***     | satou@gmail.com        | P001   | **スイムウェア**| 1    |
| 1002   | 2024-10-15 | 002    | ゴールデンエイジ岡本 | 大阪府***      | okamoto@gmail.com      | P002   | 枕 | 2    |
| 1003   | 2024-10-20 | 003    | プロボーラー田中     | 北海道***     | tanaka@gmail.com       | P003   | カメラ     | 1    |
| 1004   | 2024-10-25 | 004    | バックエンド鈴木 | 京都***      | suzuki@gmail.com       | P004   | ゴルフクラブ      | 3    |
| 1005   | 2024-10-25 | 005    | テニスプレイヤー橋本 | 東京都***      | hashimoto@gmail.com       | P005   |**スイムウェア**| 1    |

ここで、商品名の「水着」が「スイムウェア」に変更されたとします。これは、DB内のすべての関連データに影響を及ぼす可能性があり、DBの処理としては負荷が高くなります。具体的には、以下のような問題が考えられます。
- 更新漏れ
    - 「水着」という名称が複数のテーブルやレコードに存在する場合、すべての場所で変更が必要です。このとき、変更を忘れると、データの不整合が生じます

- 整合性の確保
    - 変更後のデータが正しく反映されているかどうかを確認するための追加のコストがかかります

それでは、商品テーブルを別テーブルとして持ってみましょう。

|商品ID|商品名|個数|
|:--------|:---------|:-------------|
| P001    | **スイムウェア**|     1        |
| P002    |     枕    |     2        |
| P003    |   カメラ   |     1        |
| P004    |   ゴルフクラブ|     3        |
| P005    | **スイムウェア**|     1        |

そうした場合、それぞれの注文は参照しているのは商品テーブルとなります。
商品の名前が変わった場合は、商品テーブルにある「商品名」を変更すれば済むようになります。
このように、DBとして扱いやすいようにテーブルを分割や統合する作業を**正規化**と言います。

つまり、**概念スキーマは外部スキーマを正規化したもの**と言えます。
概念スキーマの段階で柔軟性を持つようにテーブル間の関係を整理しておけば、必要な抽出データを変更したいと思ったときに、テーブル定義を変更することなく、抽出方法を変えるだけで、データを取得することができます。

### *内部スキーマ（物理層）*
内部スキーマは、一言で言えば「具体的なテーブル定義」であり、概念スキーマで正規化したテーブルをDBの物理的なデータに置き換えたもののことを指します。
カラム名やデータ型を決めたり、インデックスを張るか決めたりします。
つまり、データがどのように保存され、DBにアクセスされるかを定義し、DBの実装に関連する低レベルの詳細を扱うレイヤーです。

例えば、このように具体的なテーブルを定義しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3763692/ad6570e7-04f9-9d0f-afd7-53bdd69325ab.png)

注文IDは外部制約だから商品テーブルではFK(Foreign Key：外部キー)制約をかけた方が良さそうだな、顧客名のメールアドレスには重複してはいけないから一意制約（UN:UNIQUE）をかけようといった具合です。

## 3層スキーマのメリット・デメリットについて
3層スキーマはDBの管理において革新的なアプローチである一方、優れた特性と同時に幾つかの課題を抱えています。

### *データの独立性の保証*
データの独立性は、DBでもっとも重要な属性の一つであり、3層スキーマで最大のメリットと言えます。
この独立性は、システムの拡張性と適応性を向上させ、継続的な変化に柔軟に対応できるようにします。具体的には、アプリケーションは物理データに直接的に依存しないため、以下のようなメリットがあります
- 変更の容易さ
    - コードの修正やデータの格納方法の変更が容易で、アプリケーションが変化に迅速に対応できます
しかし、完全なデータの独立性を実現することは難しく、データの一貫性を維持するための複雑な構造とアルゴリズムが必要になることもあります。

### *データ管理の効率化*
データの格納、アクセス、更新の管理が容易であり、ユーザーのインタラクションとデータの物理的な操作を分離することで、多くのユーザーが一度にDBにアクセスできます。
この効率的な管理は、以下のメリットがあります。
- DBの保守や管理にかかるコスト削減
- 整合性の維持
- システムの可用性の確保 

しかし、これには高度な技術スキルと専門知識が必要であり、小規模プロジェクトでは導入が困難であると感じるかもしれません。特にリソースが限られている場合、DB管理の最適化には慎重な検討が求められます。


### *パフォーマンスと信頼性の向上*
高速なデータアクセスと効率的なデータ管理により、システム全体のパフォーマンスと信頼性を向上させます。
これは正確な情報の提供、迅速な問い合わせのレスポンス、効率的なデータ管理を保証します。
これらはすべて、最適なユーザーエクスペリエンスを提供し、システムの全体的な評価を向上させるのに役立ちます。

しかし、これらを実現するためには、詳細な計画と開発、テストが求められます。

### *階層的設計の挑戦と制約*
3層スキーマは、内部スキーマ、概念スキーマ、外部スキーマという3つのスキーマを有効に結びつけることにより、システム全体の堅牢性と柔軟性を向上させます。

しかし、**階層的設計**は、各スキーマの間で一貫性と整合性を維持することを必要とします。これは、設計者と開発者にとって一定の挑戦をもたらします。
また、各スキーマのロールを正しく理解し、正確に実装することは、発達途上のデータベース技術者にとっては困難であるかもしれません。

## まとめ
スキーマとは「DBの構造や設計、関係性を定めたもの」で、その構造や設計を**外部スキーマ・概念スキーマ・内部スキーマ**の３つのレイヤーで分けたものを3層スキーマという。

:::note 
- 外部スキーマ（見た目）
    - 利用者やアプリケーションから見たDBの見た目
- 概念スキーマ（データ構造）
    - 開発者から見たDBの論理的構造
- 内部スキーマ
    - 具体的なテーブル定義やインデックスの設定、物理的なデータの格納方法
:::
この3層スキーマは大規模なデータベースの効果的な管理が可能となり、さまざまなユーザー要件を同時に満たす能力を保証します。また、データの整合性やセキュリティの確保、効率的なデータアクセスを実現します。