SQLite | ゼロからはじめるSQL、30日で習得するSQLite:実践 - Day26 設計改善

SQL SQLite
スポンサーリンク

Day26 前半のゴール

「“とりあえず動く設計”から“一生付き合える設計”に育てる感覚をつかむ」

Day25 までで、顧客・商品・注文のテーブルを分けて、
それなりに“ちゃんとした”売上管理ができるようになりました。

Day26 のテーマは 設計改善:テーブル分割・正規化
ゴールはこうです。

「一応動いているテーブル設計」を眺めて、
どこにムダや重複があるかを見つける
それを「テーブル分割」「正規化」という形で改善するイメージを持つ

ここでは、難しい理論を増やすというより、
「今ある設計を、どう“育てていくか”」という視点を身につけることを重視します。


まずは“ちょっとダメな設計”をあえて用意する

「最初から完璧じゃなくていい、むしろそこからが設計の本番」

いきなり正しい正規化の話をしても、
「ふーん」で終わりがちです。

なので、あえて少しダメなテーブルを出します。
例えば、こんな顧客テーブルを想像してください。

CREATE TABLE customers_bad (
  id            INTEGER PRIMARY KEY,
  name          TEXT    NOT NULL,
  email         TEXT    NOT NULL,
  phone         TEXT,
  zip_code      TEXT,
  address       TEXT,
  prefecture    TEXT,
  city          TEXT,
  street        TEXT
);
SQL

一見、普通に使えそうです。
でも、よく見ると「住所っぽい情報」がバラバラに入っています。

zip_code と address が両方ある
prefecture / city / street と address が重複している
住所の持ち方のルールが曖昧

こういう「なんとなく増やしたカラム」が、
あとからじわじわ効いてきます。

ここから、「どこをどう分けるとスッキリするか」を考えるのが、
設計改善・正規化の入り口です。


正規化を“現場の言葉”に言い換える

「同じことを何度も書かない」「意味の違うものを同じ場所に置かない」

正規化という言葉は堅いですが、
やっていることはシンプルです。

同じ情報を何度も書かないようにする
意味の違う情報を、同じカラムや同じテーブルに押し込まない

例えば、顧客テーブルに「都道府県名」を文字列で持っているとします。

東京都
東京
都内

のように、表記ゆれが起きます。
これを放置すると、「都道府県別集計」が地獄になります。

ここで出てくるのが「テーブル分割」です。
都道府県を別テーブルにして、
顧客テーブルからは「都道府県ID」だけを持つようにする。

これが、正規化を現場の言葉にしたときの一つの形です。


住所を例にしたテーブル分割

「“マスタ”と“実データ”を分ける」

さっきの customers_bad を、少しマシな形にしてみます。

まず、「都道府県」をマスタテーブルにします。

CREATE TABLE prefectures (
  id   INTEGER PRIMARY KEY,
  name TEXT NOT NULL UNIQUE
);
SQL

ここに、

1, '北海道'
2, '青森県'
…
13, '東京都'
…

のように、都道府県一覧を入れておきます。

次に、顧客テーブル側はこう変えます。

CREATE TABLE customers (
  id             INTEGER PRIMARY KEY,
  name           TEXT    NOT NULL,
  email          TEXT    NOT NULL UNIQUE,
  phone          TEXT,
  prefecture_id  INTEGER,
  city           TEXT,
  street         TEXT
);
SQL

ポイントは二つです。

都道府県名そのものは持たず、prefecture_id だけを持つ
住所を「都道府県」「市区町村」「番地・建物」など、意味ごとに分ける

これにより、

都道府県名の表記ゆれがなくなる
都道府県名を変更したいとき、prefectures だけ直せばよい
顧客テーブルのカラムが少しスッキリする

という効果が出ます。

これが、「マスタテーブルに切り出す」という典型的な正規化の一歩です。


「1つのカラムに複数の意味を詰め込まない」という感覚

「カンマ区切り・スラッシュ区切りは“危険信号”」

もう一つ、よくある設計の悪い例を出します。

CREATE TABLE customers_bad2 (
  id            INTEGER PRIMARY KEY,
  name          TEXT    NOT NULL,
  email         TEXT    NOT NULL,
  tags          TEXT    -- 例: 'VIP,メルマガ,キャンペーンA'
);
SQL

一見便利そうですが、tags にカンマ区切りで複数の情報を詰め込んでいます。

「VIP の顧客だけ取りたい」と思ったとき、
WHERE tags LIKE '%VIP%' のような、
雑な検索をせざるを得ません。

これは、正規化の観点から見ると完全にアウトです。

本来は、「顧客」と「タグ」は別テーブルにして、
中間テーブルで多対多の関係を表現するのが筋です。

CREATE TABLE tags (
  id   INTEGER PRIMARY KEY,
  name TEXT NOT NULL UNIQUE
);

CREATE TABLE customer_tags (
  customer_id INTEGER NOT NULL,
  tag_id      INTEGER NOT NULL,
  PRIMARY KEY (customer_id, tag_id)
);
SQL

こうしておけば、

「VIP タグを持つ顧客」
「メルマガタグを持つ顧客」

などを、JOIN で素直に取れるようになります。

ここでの重要な感覚は、

1つのカラムに「複数の値」や「複数の意味」を詰め込んだら負け

ということです。
カンマ区切り・スラッシュ区切り・JSON 文字列などは、
「本当は別テーブルにすべき情報を無理やり押し込んでいる」サインになりがちです。


正規化とパフォーマンスの関係をざっくり押さえる

「まずは“きれいに分ける”、そのあと“必要ならまとめる”」

正規化の話をすると、よく出てくる心配がこれです。

「テーブルを分けすぎると、JOIN が増えて遅くなるのでは?」

これは半分正しくて、半分誤解です。

設計の基本方針としては、

まずは正規化して“意味的にきれいな形”にする
その上で、本当に必要な箇所だけ、ビューやキャッシュテーブルで“まとめておく”

という順番が健全です。

最初から「JOIN が面倒だから 1 テーブルに詰め込む」とやると、
短期的には楽でも、長期的には必ず破綻します。

一方で、
「分析用に、顧客×都道府県×売上をまとめたビューを作る」
「バッチで日次集計テーブルを作っておく」

といった“読み取り専用のまとめ方”は、
正規化と矛盾しません。

Day26 では、

正規化=テーブルを意味ごとに分ける
パフォーマンス対策=必要に応じて“読み取り用のまとめ”を別途用意する

という切り分けを、頭の中に置いておいてください。


セキュリティの視点から見た設計改善

「“どこに何があるか”をはっきりさせることが、守りの第一歩」

正規化やテーブル分割は、
セキュリティ的にも大きな意味を持ちます。

例えば、
顧客テーブルに「パスワードハッシュ」「クレジットカード情報」「住所」「権限フラグ」など、
何でもかんでも詰め込んでいるとします。

この状態だと、

「このテーブルにアクセスできる人は、全部見えてしまう」

という危険な状況になります。

一方で、

認証情報は user_credentials
権限は user_roles
個人情報は customer_profiles

のように分けておけば、

「このアプリは顧客プロフィールだけ参照」
「このバッチは売上だけ参照」

といった形で、アクセス範囲を絞りやすくなります。

つまり、

正規化=意味ごとにテーブルを分けることは、
「どこに何があるか」を明確にし、
「どこまで見せるか」を制御しやすくする、という意味で
セキュリティの土台にもなります。


Day26 前半のまとめ

設計改善・正規化の出発点は、「今あるテーブルのどこに重複や意味の混在があるか」を見つけること。
住所や都道府県のような“共通で使う情報”は、マスタテーブルに切り出し、元のテーブルからは ID だけを持たせることで、表記ゆれや修正漏れを防げる。
1つのカラムに複数の値(カンマ区切りなど)や複数の意味を詰め込むのは、正規化の観点から危険信号であり、本来は別テーブルや中間テーブルで表現すべき関係であることが多い。
正規化は「まず意味的にきれいに分ける」ためのもので、パフォーマンスが必要な箇所はビューや集計テーブルなど“読み取り専用のまとめ”で補う、という役割分担を意識するとよい。
テーブルを意味ごとに分けておくことは、「どこに何の情報があるか」を明確にし、アクセス範囲を絞りやすくするという意味で、セキュリティ設計の土台にもなる。

後半では、
実際に「悪い設計 → 改善後の設計」を具体的な例で並べて比較しながら、
第1〜第3正規形の考え方を“用語抜きでも説明できるレベル”まで落とし込んでいきます。

タイトルとURLをコピーしました