はじめに
こんにちは。ITコンサルをやっているまるやきです。
明けましておめでとうございます。今年もどうぞよろしくお願いいたします。
本記事では、達人に学ぶDB設計徹底指南書を読んで学んだことをまとめていきます!
論理設計と物理設計
- 論理設計とは: 物理的な制約(ハードウェアや特定のDBMS)に依存しない、概念データモデルに基づくデータとその関係性の設計。「どのようなデータを扱うか」を定義する。エンティティの抽出やER図の作成、正規化が主なステップ。
- 物理設計とは: 論理設計で定義されたモデルを、特定のRDBMS製品やハードウェア上でどのように格納し動作させるかを決定する設計。テーブルやインデックスの作成、データ型の選定、サイジング(容量見積もり)などが含まれる。
- 設計のステップと関係性: 論理設計から物理設計への「片道切符」が基本。物理的な制約(パフォーマンス問題など)を理由に論理設計をあとから歪めるのは、本来避けるべき事態である。
- トレードオフ: 「データの無矛盾性(正規化による一貫性)」と「検索パフォーマンス(非正規化による速度向上)」はしばしばトレードオフになる。原則として論理設計によるデータ品質を優先し、パフォーマンステストを経た上で初めて物理設計のアプローチ(チューニングやあえての非正規化等)を検討する。
正規化
- 正規化の目的: データの重複を排除し「1つの事実は1か所に」を徹底することで、更新異常(一部だけ更新されてデータが矛盾する等)を防ぐこと。
- 第1正規形: 「一つのセルには一つの値しか含まれない(スカラ値の原則)」。配列やカンマ区切りの文字列を持たせるのはNG。
- 第2正規形: テーブルが複合主キーを持つ場合、主キーの一部にのみ関数従属する列(部分関数従属)を別のテーブルに切り出す。
- 第3正規形: 主キー以外の列に従属する列(推移的関数従属)を別のテーブルに切り出し、テーブル間の関係を整理する。
- 正規化のメリットとデメリット(パフォーマンスへの影響): メリットはデータの整合性が強固に保たれること。デメリットは、テーブルが細かく分割されるため、複雑な条件での検索時に多数のテーブルを結合(JOIN)する必要が生じ、パフォーマンスが低下するリスクがあること。
- 非正規化(サロゲートキーや冗長な列の追加)の判断基準とリスク: パフォーマンス要件を満たせない場合の最終手段として非正規化を検討する。ただしデータ不整合のリスクが高まるため、バッチ処理やアプリケーション側のロジックで整合性を担保する高いコストを背負う覚悟が必要。
パフォーマンス
- インデックス(主にB-treeアルゴリズム)の基礎と設計方針: B-treeインデックスは木構造によってデータを探索し、等価検索や範囲検索において O(log N) の速度でアクセス可能。WHERE句の絞り込み条件やJOINの結合条件で使用される列にインデックスを張るのが基本。
- インデックスが効かないケースとその対応策: インデックス列に対し演算を行っている場合(例:
WHERE col * 1.1 > 100)、IS NULL検索、否定形(<>,!=)、中間・後方一致のLIKE検索、暗黙の型変換が行われている場合などは、フルスキャンに陥りやすい。設計段階からこれらの条件を回避するSQLやスキーマを組む。 - 統計情報とオプティマイザの役割: DBMSのオプティマイザは、テーブルの統計情報(行数、データの直近のバラつき・カーディナリティなど)を元に最適な実行計画を立てる。カーディナリティが高い(値のバリエーションが多い)列にインデックスを張るのが効果的。統計情報が古いままだと間違った実行計画が選ばれるため、運用での定期的な更新が必須。
- 結合(JOIN)の内部動作(Nested Loops, Hash, Sort Merge)とチューニング:
- Nested Loops: 駆動表(外側)の1行ずつに対し内部表をスキャン。駆動表を小さくし、内部表の結合列にインデックスがある状態が最適解。
- Hash: 結合キーでハッシュ表を作成。メモリを消費するが大容量データの結合に有利。
- Sort Merge: 両テーブルを結合キーでソートしてマージ。ソートのメモリやCPUコストが高い。
バッドノウハウ(アンチパターン)
- 非スカラ値(配列やカンマ区切り)の格納: 第1正規形違反。検索条件や集計が極めて複雑になり、パフォーマンスもインデックスが効かず最悪になる初歩的かつ致命的なミス。
- 単一参照テーブル(何でも1つのマスタにまとめる)の罠: あらゆるコードと名称の組み合わせを1つの「区分マスタ」「汎用マスタ」に統合する手法。列のデータ型を可変長文字列(VARCHAR等)にせざるを得ず、機能的な制約(外部キーなど)も設定できなくなり、SQLも複雑化する百害あって一利なしの設計。
- テーブル分割・列分割による局所的なパフォーマンス最適化の落とし穴: データを年度ごと等にテーブル分割(水平分割)したり、よく使う列だけ別テーブルに切り出す(垂直分割)のは、アプリケーション側のSQLを著しく複雑化させる。DBMS備え付けのパーティショニング機能の利用を最優先にすべき。
- 不適切なキー設計・ダブルマスタなど: 独立したマスタを複数作ってしまうダブルマスタは、データの一貫性を損ねる。また、意味のある値(業務的なコード等)を主キーにするか、無意味なサロゲートキー(自動採番ID等)にするかは変更耐性を考慮し慎重に選ぶ。
- 回避策・あるべき正規化された設計: 原則として「1つの事実は1つの場所に」。正しく正規化を行い、安易なテーブル統合や分割に逃げず、DBMSの機能(インデックス、オプティマイザの理解、パーティション)を正しく活用してパフォーマンスを維持する。
まとめ・感想
本書を通じて、DB設計の良し悪しがシステムの「寿命」や「メンテナンス性」に直結することを改めて学んだ。 特にパフォーマンス改善のためにデータを汚す「非正規化」は甘い罠であり、どうしても必要な場合の最終手段として取っておき、まずは正しい論理設計(完全な正規化)からアプローチする姿勢を実業務でも徹底したい。 また、単一参照テーブルや安易な水平分割といったアンチパターンを知っておくことで、既存の悪手を見抜く目や、新規設計時に過ちを未然に防ぐ視点が養われた。今後はSQLのチューニングを行う際にも、オプティマイザの気持ちと統計情報を意識して取り組んでいきたい。