はじめに

データ設計が重要な理由

データ設計は一度決めると直せない。その理由を 5 つの事実で示す。

データ設計が重要な理由 diagram

なぜデータ設計だけは「後から直す」が通用しないのか

アプリケーションのコードは、壊れたら書き直せば済みます。画面レイアウトや UI のリファクタリングは、最悪ユーザーに影響せず翌日にはリリースできます。しかしデータ設計(テーブル構造・型・キー・正規化・制約)だけは、一度本番投入するとやり直しが極端に難しい領域です。

  • 既に保存されたデータをどうするかという移行問題が常について回る(バックフィル・ダブルライト・段階的切替)
  • 依存するクエリ・アプリ・BI レポート・外部連携がすべて同時に書き換わる必要がある
  • 巨大テーブルの ALTER は数時間〜数日のロックになり、停止時間を伴う

だからこそ、最初の設計に投じる時間は、後から払う移行コストに比べて桁違いに安いというのがデータ設計の鉄則です。本ページでは、この鉄則を支える 5 つの事実と、「最も重要」と断言するかの文脈依存性を整理します。

事実 1: データは資産そのもの — 失うと戻らない

開発の世界では「コードは書き直せるが、失われたデータは戻らない」という非対称性があります。ユーザー情報・取引履歴・コンテンツ・ログ — これらこそがサービスの本質的な価値であり、アプリはその価値にアクセスするための「窓口」に過ぎません。

  • ログイン機能が落ちても 30 分で復旧できるが、ユーザーテーブルが吹き飛んだら顧客資産そのものが消失する
  • 決済バグは返金で挽回できるが、会計データの改ざんや欠損は監査で致命傷になる
  • 推薦モデルは再学習できるが、学習元の行動ログが無ければ再現不可能

さらに、業務で扱うデータはそれを作ったアプリケーションより遥かに長く生き残ります

  • 会計・取引・人事データは法定保存期間(7〜10 年)があり、アプリがリプレイスされても消せない
  • ユーザーアカウントや取引履歴は、フレームワーク(Rails / Django / Spring 等)を何度乗り換えても受け継がれる
  • 基幹系では20〜30 年前の COBOL や Oracle の DB がそのまま現役、ということが普通に起こる

一方でアプリのフレームワークや言語、フロントエンドは数年単位で入れ替わります。つまり、

アプリの寿命 << データの寿命

この非対称性があるため、データ構造は「今のアプリに合うか」ではなく「10 年後も使える意味を持つか」で設計する必要があります。特定フレームワークの都合で列名を決めたり、今使っている ORM の制約で型を曲げたりすると、フレームワークを捨てるときに設計ごと捨てる羽目になります。

事実 2: 修正コストは時間とともに指数的に増える

同じ「users.namefirst_namelast_name に分ける」修正でも、タイミングによってコストは桁違いに変わります。

タイミングデータ量必要な作業体感コスト
設計段階(ER 図を書いている最中)0 行図と DDL を書き換えるだけ数分
開発初期(ステージングのみ)〜数百行マイグレーション追加+コード修正+DB 再構築数時間
本番リリース直後数万〜数十万行上記+既存データの機械分割(姓名判別ロジック)+UI 修正+API 互換レイヤ数日〜数週間
運用 3 年後数百万〜数千万行上記+BI レポート全部+外部連携先の調整+オンライン移行+ロック対策数ヶ月〜プロジェクト化

「設計段階で気づいていれば 5 分」が、「運用 3 年目だと 3 ヶ月の移行プロジェクト」になる、という曲線を描きます。しかも後者では分割不可能なレガシーデータ(姓名一体で登録されたまま)が永遠に残るケースも珍しくありません。

この非線形性を知っているかどうかが、設計時に「面倒だから後回し」と「今しっかり決める」を分ける判断基準になります。

事実 3: 整合性の最終砦は DB — アプリは信用できない

「NOT NULL や外部キーは ORM / バリデーションで担保しているから DB 側は緩くていい」という設計は、長期的にはほぼ確実に破綻します。理由はシンプルで、データベースに書き込む経路はアプリだけではないからです。

  • 本番障害対応で DBA が psql / sqlplus から直接 UPDATE する
  • データ移行スクリプト(Python / シェル)が一括 INSERT する
  • BI チームが分析用に別テーブルへ ETL する
  • 次の世代のアプリが別の ORM / 別のバリデーションルールで同じテーブルに書く
  • バグったバッチジョブが想定外の値を書き込む

アプリ側のチェックは「今日のこのアプリを通った場合」しか守れません。DB に NOT NULL / CHECK / FOREIGN KEY / UNIQUE が宣言されていれば、どの経路から書き込まれても整合性が強制される。これは代替できない DB だけの機能です。

詳しくは 制約(CONSTRAINT)外部キー設計 を参照してください。

事実 4: 性能は設計段階でほぼ決まる

「リリース後に遅くなったらインデックスを足せばいい」と思いがちですが、設計ミスはインデックスでは救えない領域があります。

  • 正規化不足: JSON や CSV 文字列に複数値を詰めてしまうと、条件検索で全件スキャンを避けられない
  • 主キー設計のミス: UUID v4 を主キーにすると B-Tree の挿入位置がランダムになり、数千万行規模で挿入性能が数倍劣化する(UUID インデックス
  • 外部キー/インデックス前提の JOIN: 後から大きなテーブルに複合インデックスを足そうとすると、数時間のロックや再構築が必要になる
  • 型の誤り: 数値を VARCHAR で持ったり、日時を文字列で持ったりすると、比較・範囲検索でインデックスが使われない(暗黙の型キャスト

つまり性能の 70〜80% は、インデックスやクエリチューニングではなく、最初のテーブル設計で決まっています。設計時に押さえるべき観点は インデックス設計入門高速化チェックリスト にまとめています。

事実 5: スケーラビリティの限界を決めるのは DB

アプリサーバは比較的「横に並べる」ことで簡単にスケールできます。コンテナを増やし、ロードバランサに追加すればリクエスト処理能力はほぼ線形に伸びます。一方 DB のスケールは設計・運用ともに一気に難しくなる のが現実です。

観点アプリサーバDB
スケール手段インスタンス追加(水平)リードレプリカ / シャーディング / パーティション
状態基本ステートレス状態そのものを持つ(データの整合性が絡む)
書き込みのスケール気にしなくてよい書き込みは原則 1 マスター — 分割設計が必須
運用難易度オートスケールで大半は自動化レプリ遅延・フェイルオーバ・シャード再分割など人が介在
切り戻し古いバージョンに戻すスキーマ移行後の切り戻しは極めて困難

結果として、DB はサービス成長の「天井」になりがちです。アプリ側が捌けていても、DB が限界に達すればそのサービスは成長を止めます。設計段階で次のような観点を押さえておくと、天井を遠ざけられます。

  • 読み書き比率を見積もる(読み 9 割ならレプリカで拡張しやすい/書き中心ならシャード分割を早めに検討)
  • シャーディングキーを主キーに織り込めるか(後からの付け替えは事実上移行プロジェクト)
  • 集計・分析用途は分離(リードレプリカ / データウェアハウス / CQRS)
  • ホットスポットを避ける(連番 PK の末尾集中、時系列のラストパーティション集中)

具体的なテクニックは インデックス設計入門高速化チェックリスト を参照してください。

補足: 「最も重要」かどうかは文脈次第

ここまで「データ設計は最重要」という立場で解説してきましたが、これを絶対視すると見誤ります。実際にはシステムの性質によってボトルネックの主役は変わります

システムの性質主なボトルネックデータ設計の位置づけ
業務システム / SaaS / ECDB(クエリ・スキーマ・整合性)最重要
金融 / 会計DB(整合性・監査ログ)最重要
ゲームサーバ(リアルタイム対戦)ネットワーク遅延・インメモリ状態重要だが主役ではない(永続化部分に限定)
AI 推論・機械学習基盤GPU / モデルサイズ / 推論レイテンシ学習データのパイプラインに限って重要
IoT / ストリーミングスループット・メッセージブローカ書き込みスケール設計としては重要
静的コンテンツ配信 / CDNキャッシュ・配信網管理用 DB のみ、比重は小さい

本サイト Query Go が扱う RDB は、上表でいう業務システム / SaaS / EC / 金融系の中核技術です。扱っているシステムがこの領域なら「データ設計が最重要」は正しいと考えて差し支えありません。一方、リアルタイムゲームや AI 推論など別領域では、他のレイヤと並列で検討する必要があります。

設計段階で最低限決めるべき項目

では、どの項目を設計段階で確定しておけばよいのでしょうか。後から変更コストが大きい順に並べると以下のようになります。

項目設計で決めること後回しの危険度
エンティティとテーブル分割何を 1 テーブルにし、何を別テーブルにするか(正規化)極大(全クエリが書き直し)
主キーの選び方連番整数 / UUID v7 / 自然キー のどれにするか大(FK 含めて再設計)
列の型数値 / 文字列 / 日時 / 金額(NUMERIC)/ JSON の選択大(既存データ変換が必要)
外部キーと制約FK / UNIQUE / CHECK / NOT NULL中(違反データが貯まってから足せない)
NULL 可否NULL 許容の意味はあるか、デフォルト値はどうするか中(意味論が変わる)
監査列created_at / updated_at / deleted_at を全テーブルに入れるか中(後から全テーブル ALTER)
インデックス主な検索条件と ORDER BY に合う複合インデックス小〜中(後から追加可能、ただしロック注意)

上 3 つ(テーブル分割・主キー・型)は特に「後から直す」が事実上できない領域なので、設計レビューで必ず合意を取っておきます。

よくある初期設計のアンチパターン

設計時に避けたい典型例を挙げます。いずれも初期は楽に見えて、1〜3 年後に大きな移行コストに化けるものです。

  • なんでも文字列(VARCHAR): 数値も日時も真偽も全部 VARCHAR。比較も範囲検索もインデックスも機能しなくなる
  • 1 列に CSV や JSON を詰め込む: tags = "赤,青,緑" のようにすると正規表現検索しかできず、絞り込みが全件スキャンになる
  • 主キーに業務キーを使う: メールアドレスやユーザー ID 文字列を主キーにすると、変更したい時に全テーブルの FK を張り替える羽目になる
  • 外部キーを張らない: 「アプリで担保するから」と FK を省くと、孤児レコードが年単位で積もって清掃プロジェクト化する
  • 金額を FLOAT / DOUBLE にする: 0.1 + 0.2 ≠ 0.3 になり、会計監査で数円単位のズレを追うことになる
  • 日時を文字列で持つ: タイムゾーン情報が消え、国をまたぐサービスでダブル計上・未計上が起きる
  • soft delete を途中から導入: 全クエリに WHERE deleted_at IS NULL を付け回るメンテコストが永続化する。初期に決めておく

次に読む

データ設計の重要性を押さえたら、次は具体的な設計手法に進みます。