データベース設計とは?正規化・ER図・アンチパターンを実例で解説

データベース設計とは? ― アプリケーションの「基礎工事」

データベース設計とは、アプリケーションが扱うデータの構造(テーブル、カラム、リレーション)を体系的に決定するプロセスです。建築における設計図と同じで、ここを誤ると後からの修正コストが膨大になります。テーブル構造、データ型、制約、インデックス、リレーションシップの設計が主な作業です。

家の設計図に例えると、部屋の数や配置(テーブル設計)、水道管や電気配線のルート(リレーション)、耐震構造(制約・バリデーション)を事前に決めるのがデータベース設計です。住み始めてから間取りを変えるのが大変なように、データベースの構造変更も運用開始後は困難です。

データベース設計の3つのステップ

ステップ1:概念設計
ビジネス要件を分析し、システムが扱う「エンティティ(実体)」と「リレーションシップ(関係)」を洗い出します。ER図(Entity-Relationship Diagram)を使って視覚的に表現するのが一般的です。この段階ではDBMSに依存しない抽象的なモデルを作ります。

ステップ2:論理設計
概念設計をリレーショナルモデルに変換します。テーブル、カラム、主キー、外部キー、データ型を具体的に定義します。正規化を適用してデータの重複を排除し、整合性を確保します。

ステップ3:物理設計
使用するDBMS(MySQL、PostgreSQLなど)に最適化した設計を行います。インデックス設計、パーティショニング、ストレージエンジンの選択、パフォーマンスチューニングがこの段階の作業です。

正規化とは ― なぜデータの重複を排除するのか

正規化は、データの冗長性を排除してデータの整合性を保つための手法です。段階的に進める3つの正規形が基本です。

第1正規形(1NF):各カラムが原子的(それ以上分割できない)な値を持つこと。1つのセルに複数の値(カンマ区切りなど)を入れてはいけません。

第2正規形(2NF):1NFを満たし、かつ部分関数従属を排除すること。複合主キーの一部だけに依存するカラムを別テーブルに分離します。

第3正規形(3NF):2NFを満たし、かつ推移的関数従属を排除すること。主キー以外のカラムに依存するカラムを別テーブルに分離します。

実務では第3正規形まで適用するのが標準です。ただし、読み取りパフォーマンスが重要な場面では、あえて非正規化(デノーマライゼーション)を行い、JOINの回数を減らすことも一般的な戦略です。

リレーションシップの3パターン

パターン 説明 実装方法
1対1 一方のレコードが他方の1レコードに対応 外部キー + UNIQUE制約 ユーザー ↔ ユーザー詳細
1対多 一方の1レコードが他方の複数レコードに対応 多側のテーブルに外部キーを追加 部署 → 社員(1つの部署に複数の社員)
多対多 双方のレコードが互いに複数対応 中間テーブル(交差テーブル)を作成 学生 ↔ 講座(1人が複数講座、1講座に複数学生)

データベース設計のアンチパターン ― やってはいけない設計

アンチパターン1:EAV(Entity-Attribute-Value)の乱用
属性名と値をキーバリューで格納するテーブル設計です。柔軟に見えますが、型安全性が失われ、クエリが複雑になり、パフォーマンスが大幅に低下します。JSONカラムやNoSQLの方が適切な場合が多いです。

アンチパターン2:ポリモーフィック関連
1つの外部キーカラムで複数のテーブルを参照する設計です。外部キー制約が設定できず、データの整合性が保証されません。代わりに、共通の親テーブルを作るか、テーブルごとに個別の外部キーを持たせましょう。

アンチパターン3:カンマ区切りの値
1つのカラムに「tag1,tag2,tag3」のようにカンマ区切りで複数の値を格納する設計です。検索・更新・削除がすべて困難になります。中間テーブルを使った多対多リレーションで正しく設計しましょう。

アンチパターン4:巨大テーブル
100以上のカラムを持つ「神テーブル」は、パフォーマンス低下と保守困難の原因です。責務ごとにテーブルを分割し、必要に応じてJOINで結合するのが基本です。

実務で役立つ設計のベストプラクティス

主キーはサロゲートキー(自動採番ID)を基本に:ビジネス上の値(メールアドレス、社員番号など)を主キーにすると、値の変更時に大量の外部キー更新が発生します。自動採番のIDを主キーにし、ビジネスキーにはUNIQUE制約を設定しましょう。

NOT NULL制約を積極的に使う:NULLは「値がない」という曖昧な状態を作り、バグの温床になります。NULLが本当に必要なケースを除き、NOT NULL制約とデフォルト値を設定するのが安全です。

created_at / updated_at を全テーブルに:レコードの作成日時と更新日時は、デバッグ、監査、データ分析で必ず役立ちます。全テーブルに標準で追加しましょう。

論理削除 vs 物理削除を早めに決める:削除フラグ(deleted_at)でレコードを非表示にする論理削除は復元が容易ですが、クエリに常にWHERE deleted_at IS NULLが必要になります。要件に応じて方針を統一しましょう。

よくある質問(FAQ)

Q. ER図はどのツールで書くのが良いですか?
A. 無料ならdbdiagram.io、draw.io、PlantUMLが人気です。チーム開発ではDataGrip(JetBrains)やMySQL Workbenchのリバースエンジニアリング機能も便利です。

Q. 正規化しすぎると遅くなりませんか?
A. JOINの増加によるパフォーマンス低下は起こりえます。しかし、インデックスの適切な設定で多くの場合解決します。パフォーマンス問題が計測で確認されてから非正規化を検討するのが正しい順序です。

Q. UUIDとAUTO INCREMENTのどちらを主キーにすべきですか?
A. 単一DBならAUTO INCREMENTがシンプルで高速です。マイクロサービスや分散システムではUUID(v4またはv7)が競合なく生成できるため有利です。UUID v7は時系列ソートも可能で、インデックス効率も改善されています。

まとめ

データベース設計は、アプリケーションの品質とパフォーマンスを根底から支える重要な工程です。概念設計→論理設計→物理設計の3ステップを踏み、正規化でデータの整合性を確保しつつ、アンチパターンを避けることが成功の鍵です。設計は後からの変更コストが高いため、開発の初期段階で十分な時間を投資する価値があります。

コメント