#01 データベースを設計する

データベース設計とは何か

データを保存するだけなら、テーブルを1つ作って全部のカラムを突っ込むだけでも動きます。しかし「動く」と「よい設計」はまったく別の話です。このシリーズでは、 データベース? データを整理して保存・検索できるソフトウェア。Webアプリのユーザー情報や投稿データなどはここに保存される。 設計の基礎から実践まで、ECサイトを例に丁寧に学んでいきます。

なぜ設計が大切なのか

アプリケーション開発でもっとも修正コストが高い部分のひとつが、 データベース? データを整理して保存・検索できるソフトウェア。Webアプリのユーザー情報や投稿データなどはここに保存される。 のスキーマ変更です。テーブルにカラムを追加するだけなら比較的簡単ですが、テーブルを分割したり、カラムの型を変えたりするのは大変です。本番データが入っていれば、マイグレーションの手間も跳ね上がります。

後から直すのが難しい理由は主に3つあります。

  1. 既存データの移行が必要 — 設計を変えると、すでに保存されているデータを新しい形式に変換しなければなりません
  2. アプリケーションコードへの影響 — スキーマが変わると、クエリや ORM の定義も変更が必要です
  3. ダウンタイムのリスク — 大規模なマイグレーションは本番環境に影響を与えることがあります
設計なし vs 設計あり 設計なし(Bad) orders(1テーブルに全部) id user_name user_email user_address product1_name product1_price product2_name product2_price product3_name ... 拡張不可・重複多数・集計困難 設計あり(Good) users id PK name email products id PK name price orders id PK user_id FK total_price order_items id PK order_id FK product_id FK quantity 整合性・拡張性・保守性が高い
図1: 設計なしvs設計ありの比較

論理設計と物理設計

データベース設計は大きく2つのフェーズに分かれます。

論理設計

論理設計は「何のデータを、どういう関係で保存するか」を決める工程です。特定のデータベースエンジン(MySQL や PostgreSQL など)に依存しない、概念レベルの設計です。

  • エンティティ(テーブルに対応する概念)の洗い出し
  • エンティティ間の関係(リレーション)の定義
  • 正規化? データの重複をなくし、更新時の不整合を防ぐためにテーブルを分割する設計手法。第1〜第3正規形などの段階がある。整理されたDBはメンテナンスしやすくなる。 によるデータの整理
  • ER図? Entity-Relationship Diagram。エンティティ(テーブル)とその間の関係(リレーション)を視覚化した設計図。DBの構造を理解・共有するために使う。 の作成

物理設計

物理設計は論理設計をもとに、実際のデータベースエンジン上で動くスキーマを定義する工程です。

  • テーブル? データベース内のデータの入れ物。Excelのシートのように行と列でデータを管理する。 カラム? テーブルの列のこと。「名前」「メールアドレス」「作成日時」など、データの項目ごとに定義する。 の具体的な定義
  • データ型の選択(VARCHAR の長さ、INT か BIGINT か、など)
  • インデックス? テーブルの検索を高速化するためのデータ構造。本の索引のように、特定の列の値から行の位置をすばやく特定できる。検索は速くなるが、書き込みはやや遅くなる。 の設計
  • パーティショニングなどの最適化

設計の流れ

データベース設計の流れ ①要件整理 ・何を管理するか ・どう操作するか ・アクセス頻度 ②エンティティ ・もの・ことを列挙 ・属性を決める ・主キーを選ぶ ③正規化 ・重複排除 ・1NF→2NF→3NF ・テーブル分割 ④ER図 ・関係を図示 ・チームでレビュー ・合意形成 ⑤実装 DDL 作成 INDEX ※ 設計は反復的なプロセス。実装後も見直しを続ける
図2: 要件→ER図→スキーマ→実装のフロー

実際の設計は次のような流れで進めます。

  1. 要件の整理 — 何のシステムか、どんな操作が必要かを整理します
  2. エンティティの洗い出し — 管理が必要な「もの」や「こと」を列挙します
  3. 正規化 — 重複やデータの不整合が起きないよう構造を整理します
  4. ER図の作成 — テーブル間の関係を図示します
  5. DDL の作成CREATE TABLE 文を書きます
  6. レビューと調整 — 実際のユースケースに合わせて見直します

悪い設計の例

ECサイトで「注文」データを管理する場合、何も考えずに設計するとこうなりがちです。

CREATE TABLE orders (
  id INT PRIMARY KEY,
  user_name VARCHAR(100),
  user_email VARCHAR(255),
  user_address TEXT,
  product1_name VARCHAR(100),
  product1_price INT,
  product1_qty INT,
  product2_name VARCHAR(100),
  product2_price INT,
  product2_qty INT,
  product3_name VARCHAR(100),
  product3_price INT,
  product3_qty INT
);

この設計には深刻な問題があります。

  • 拡張できない — 4商品以上を注文できない。カラムを増やすしかない
  • データの重複 — ユーザー情報が注文ごとに重複する。住所が変わっても古い注文には古い住所が残る
  • 集計が困難 — 「商品Xの総売上」を計算するのに複数カラムをスキャンしなければならない
  • NULL だらけ — 1商品しか注文しない場合、product2_*product3_* はすべて NULL になる

よい設計の特徴

良いデータベース設計には次の特徴があります。

データの重複がない

同じデータが複数の場所に保存されていません。ユーザーの住所はユーザーテーブルに1カ所だけ存在します。

更新・削除・挿入に異常が起きない

  • ユーザーの住所が変わったら、1箇所を更新するだけで済む
  • 注文を削除してもユーザー情報は消えない
  • 新しい商品カテゴリを追加するのに特別な操作が不要

関連するデータが適切に結びついている

外部キー? 別のテーブルの主キーを参照するカラム。テーブル間の関係を表す。例:投稿テーブルの`user_id`でユーザーテーブルを参照。 によって、存在しない商品への注文や、存在しないユーザーからの注文が入らないよう制約できます。

拡張しやすい

新しい要件が来たとき(レビュー機能を追加する、など)に既存のテーブルを大幅に変えなくて済む構造になっています。

まとめ

設計に時間をかけることは、後々の修正コストを大幅に下げます。最初は「難しそう」と感じるかもしれませんが、決まったパターンがあるので、繰り返し練習することで自然に身につきます。

次回は、ECサイトを例にどんなエンティティが必要かを洗い出していきます。