SQLの正規化とテーブル設計を完全ガイド!初心者でもわかるデータベースの整理方法
新人
「データベース設計って、どんなことを意識すればいいんですか?」
先輩
「データベースの設計では、正規化がとても重要なんだ。データの重複を減らして、一貫性を保つためのルールなんだよ。」
新人
「正規化って何ですか?具体的にどういうメリットがあるんでしょうか?」
先輩
「いい質問だね!正規化をすることで、データの無駄をなくし、変更しやすいデータ構造を作れるんだ。具体的な例を使って説明するよ!」
1. 正規化とは?
正規化とは、データの冗長性を減らし、データの整合性を保つためにテーブルを分割するプロセスです。
正規化を行うことで、以下のようなメリットがあります。
正規化のメリット
- データの重複を減らせる - ストレージを節約し、データの一貫性を維持できる
- データ更新が簡単になる - 1か所を変更するだけで済むため、更新ミスが減る
- 検索が高速化される - 不必要なデータの読み込みを減らし、クエリの処理速度が向上する
正規化のステップ
データベースの正規化には、以下のような段階があります。
- 第1正規形(1NF) - データの「原子性」を確保する
- 第2正規形(2NF) - 部分関数従属を排除する
- 第3正規形(3NF) - 推移的関数従属を排除する
まずは、第1正規形(1NF)のルールについて詳しく見ていきましょう。
2. 第1正規形(1NF)のルールと適用例
第1正規形(1NF)のルールは、すべてのカラムが単一の値を持つことです。
つまり、1つのセルに複数のデータを入れないようにする必要があります。
1. 第1正規形のルール
- 各カラムには
単一の値しか含めない - データは
繰り返しのグループを持たない - 各行を一意に識別できる
主キーが必要
2. 1NFに違反しているテーブルの例
以下のテーブルは、1つのセルに複数の値(担当プロジェクト)が入っており、1NFに違反しています。
非正規化(1NF違反)の例
| employee_id | name | projects |
|---|---|---|
| 1 | 田中 太郎 | プロジェクトA, プロジェクトB |
| 2 | 佐藤 花子 | プロジェクトC |
| 3 | 鈴木 一郎 | プロジェクトA, プロジェクトC |
このままだと、プロジェクトごとに検索や更新がしにくい状態です。
3. 第1正規形に正規化する
1つのセルに複数の値を含めないように、テーブルを分割して正規化します。
正規化後のテーブル
employees(社員テーブル)
| employee_id | name |
|---|---|
| 1 | 田中 太郎 |
| 2 | 佐藤 花子 |
| 3 | 鈴木 一郎 |
projects(プロジェクトテーブル)
| project_id | project_name |
|---|---|
| 101 | プロジェクトA |
| 102 | プロジェクトB |
| 103 | プロジェクトC |
employee_projects(社員-プロジェクトのリレーション)
| employee_id | project_id |
|---|---|
| 1 | 101 |
| 1 | 102 |
| 2 | 103 |
| 3 | 101 |
| 3 | 103 |
このように、1つのカラムに複数の値を入れるのではなく、新しいリレーションテーブル(employee_projects)を作成して、データを正規化しました。
次のセクションでは、第2正規形(2NF)のルールと適用例について解説します。
3. 第2正規形(2NF)のルールと適用例
第2正規形(2NF)は、第1正規形(1NF)を満たしたうえで、主キーに完全に依存していないデータを別のテーブルに分離するルールです。
1. 第2正規形のルール
- まず、第1正規形(1NF)を満たしていること
- 部分関数従属(主キーの一部にしか依存しないデータ)を排除する
2. 2NFに違反しているテーブルの例
以下のテーブルでは、employee_idとproject_idが複合主キーになっていますが、project_nameがproject_idのみに依存しており、部分関数従属が発生しています。
非正規化(2NF違反)の例
| employee_id | employee_name | project_id | project_name |
|---|---|---|---|
| 1 | 田中 太郎 | 101 | プロジェクトA |
| 1 | 田中 太郎 | 102 | プロジェクトB |
| 2 | 佐藤 花子 | 103 | プロジェクトC |
| 3 | 鈴木 一郎 | 101 | プロジェクトA |
このままだと、project_nameがproject_idのみに依存しているため、冗長なデータが生まれます。
3. 第2正規形に正規化する
project_nameを独立したprojectsテーブルに分離し、冗長性を排除します。
employees(社員テーブル)
| employee_id | employee_name |
|---|---|
| 1 | 田中 太郎 |
| 2 | 佐藤 花子 |
| 3 | 鈴木 一郎 |
projects(プロジェクトテーブル)
| project_id | project_name |
|---|---|
| 101 | プロジェクトA |
| 102 | プロジェクトB |
| 103 | プロジェクトC |
employee_projects(社員-プロジェクトのリレーション)
| employee_id | project_id |
|---|---|
| 1 | 101 |
| 1 | 102 |
| 2 | 103 |
| 3 | 101 |
4. 第3正規形(3NF)のルールと適用例
第3正規形(3NF)は、第2正規形を満たしたうえで、主キーに直接関係しないデータを分離するルールです。
1. 第3正規形のルール
- 第2正規形(2NF)を満たしていること
- 推移的関数従属(主キーに直接関係しないデータ)がない
2. 3NFに違反しているテーブルの例
以下のテーブルでは、department_nameがdepartment_idに依存しており、推移的関数従属が発生しています。
非正規化(3NF違反)の例
| employee_id | employee_name | department_id | department_name |
|---|---|---|---|
| 1 | 田中 太郎 | 10 | 営業部 |
| 2 | 佐藤 花子 | 20 | マーケティング部 |
3. 第3正規形に正規化する
department_nameを別のテーブルに分離し、冗長性を排除します。
departments(部署テーブル)
| department_id | department_name |
|---|---|
| 10 | 営業部 |
| 20 | マーケティング部 |
employees(社員テーブル)
| employee_id | employee_name | department_id |
|---|---|---|
| 1 | 田中 太郎 | 10 |
| 2 | 佐藤 花子 | 20 |
次のセクションでは、非正規化のメリット・デメリットについて解説します。
7. 正規化の進め方と実践的なテーブル設計の流れ
データベース設計では、適切な正規化を行うことで、データの整合性を保ち、管理しやすい構造を作ることができます。ここでは、実践的な正規化の進め方を紹介します。
1. 正規化の基本的な流れ
- 要件定義 - どのようなデータを扱うのかを整理する
- 第1正規形(1NF) - すべてのカラムを単一の値にする
- 第2正規形(2NF) - 部分関数従属を排除する
- 第3正規形(3NF) - 推移的関数従属を排除する
- 最適化 - パフォーマンスのために非正規化やインデックスを考慮する
2. 具体的なテーブル設計の例
以下のようなデータを扱うシステムを設計するとします。
ユーザーが商品を購入するECサイトのデータ
最初に、次のようなordersテーブルを作成しました。
| order_id | customer_name | product_name | price |
|---|---|---|---|
| 1 | 田中 太郎 | スマートフォン | 80000 |
| 2 | 佐藤 花子 | ノートパソコン | 120000 |
| 3 | 田中 太郎 | ワイヤレスイヤホン | 15000 |
このままだと、customer_nameやproduct_nameが重複し、データ更新がしにくい状態です。
3. 正規化を適用したテーブル構成
customers(顧客テーブル)
| customer_id | customer_name |
|---|---|
| 1 | 田中 太郎 |
| 2 | 佐藤 花子 |
products(商品テーブル)
| product_id | product_name | price |
|---|---|---|
| 101 | スマートフォン | 80000 |
| 102 | ノートパソコン | 120000 |
| 103 | ワイヤレスイヤホン | 15000 |
orders(注文テーブル)
| order_id | customer_id | product_id |
|---|---|---|
| 1 | 1 | 101 |
| 2 | 2 | 102 |
| 3 | 1 | 103 |
このように分割することで、データの一貫性を保ち、管理しやすい構造になります。
8. 正規化とパフォーマンス(インデックス・リレーション)
正規化によってデータの冗長性は減りますが、結合(JOIN)が増えることでパフォーマンスが低下することがあります。
1. インデックスを活用する
インデックスを適切に設定することで、結合時の検索パフォーマンスを向上できます。
CREATE INDEX idx_customer_id ON orders (customer_id);
CREATE INDEX idx_product_id ON orders (product_id);
2. 非正規化の適用
パフォーマンスが求められる場合、一部のデータを非正規化して冗長性を持たせることもあります。
ALTER TABLE orders ADD COLUMN product_name VARCHAR(255);
UPDATE orders o
JOIN products p ON o.product_id = p.product_id
SET o.product_name = p.product_name;
このように、一部の情報をordersテーブルに直接持たせることで、検索の速度を向上させることができます。
9. 実践!適切なテーブル設計でデータベースを最適化する方法
最後に、実際のシステム開発でよくある設計ミスと、それを防ぐ方法を紹介します。
1. よくある設計ミス
- テーブルが大きくなりすぎる → データを適切に分割する
- 不要なデータを持たせすぎる → 本当に必要なカラムだけを設計する
- インデックスの設定が不適切 → 適切なインデックスを設定する
2. 最適なテーブル設計のポイント
以下のポイントを意識すると、データベースのパフォーマンスが向上します。
- データの整合性を保ちつつ、最小限のカラムにする
- 適切なリレーションを設定し、外部キー制約を活用する
- インデックスを適切に設定し、検索を最適化する
- 必要に応じて非正規化を行い、パフォーマンスを向上させる
正規化を適切に行い、パフォーマンスを考慮したテーブル設計をすることで、効率的なデータベースを構築できます。