0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

テーブル正規化と非正規化の設計判断

Last updated at Posted at 2025-10-03

はじめに

データベースを設計するときに必ず話題に出るのは、「正規化」と「非正規化」についてです。
正規化は冗長なデータを排除して一貫性を保つ基本的な手法ですが、実務ではあえて非正規化して冗長にデータを持たせる設計もよく行われます。

この記事では、正規化と非正規化の違いや、それぞれのメリット・デメリットを整理し、どういう状況でどちらを選択すべきかを解説していきます。

正規化とは

正規化とは、データの冗長性を排除し、整合性を保ちやすくするための設計手法。

正規化の段階

第1正規形(1NF)

1つのセルには1つのデータだけを入れるようにする。
(例)電話番号を「tel1, tel2, tel3」と列に持たず、別テーブルに分ける。
(同じ意味の値を「カラムの繰り返し」で表しているから「1セル1値」のルールに反している)
正規化前

customers
---------------------------------------------
id | name   | tel1       | tel2       | tel3
---------------------------------------------
1  | 田中   | 090-xxxx   | 03-xxxx    | NULL

正規化後

customers
------------
id | name
------------
1  | 田中

customer_phones
---------------------------------------------
id | customer_id | phone_type | phone_number
---------------------------------------------
1  | 1           | mobile     | 090-xxxx
2  | 1           | home       | 03-xxxx

【正規化前のデメリット】
①上限が決まってしまう
 「電話番号は3つまで」って勝手に制限がかかる。将来「4つ目」が必要になったらカラム追加という設計変更が必要。
②検索や集計がややこしい
 例えば「03で始まる番号を持つ顧客」を探す時、tel1, tel2, tel3 全部に検索条件を書かなきゃいけない。
③NULLだらけになる
 ほとんどの顧客は電話番号1つだけなのに、tel2, tel3 が常に空欄になる。

第2正規形(2NF)

主キーの一部にしか関係しないデータは別テーブルに移す。
(例)受注テーブル(注文ID+商品IDがキー)に「顧客住所」を持っていたら分離する。
顧客情報を別テーブルに持っている

orders
--------------------------------
order_id | product_id | address
--------------------------------
1        | A001       | 東京都港区...
2        | B003       | 東京都港区...

正規化後

customers
----------------------
id | name | address
----------------------
1  | 田中 | 東京都港区...

orders
-----------------------------------
order_id | product_id | customer_id
-----------------------------------
1        | A001       | 1
2        | B003       | 1

第3正規形(3NF)

主キーと直接関係のないデータは別テーブルに移す。
(例)社員テーブルに「部署ID」と「部署名」が両方入っていたら、部署名は部署マスタに分ける。

employees
------------------------------------------------------
employee_id | name   | department_id | department_name
------------------------------------------------------
1           | 佐藤   | D01           | 営業部
2           | 鈴木   | D01           | 営業部
3           | 高橋   | D02           | 開発部

正規化後

departments
----------------------
id  | name
----------------------
D01 | 営業部
D02 | 開発部

employees
-------------------------------------
employee_id | name   | department_id
-------------------------------------
1           | 佐藤   | D01
2           | 鈴木   | D01
3           | 高橋   | D02

非正規化とは

非正規化(Denormalization)は、あえて冗長性を持たせる設計のこと。

メリット

過去の状態を保持できる

非正規化は「当時の情報を残す」ためにも有効。
たとえば請求書に「発行当時の住所」や「当時の顧客名」を保存しておけば、後から顧客が引っ越したり改名しても、過去の請求書を正しく再現できる。
単なる冗長ではなく、履歴として意味を持たせる設計。

読み取りが速くなる

JOINを使わずに1つのテーブルだけで情報が完結するため、クエリがシンプルになる。
たとえば「請求書一覧」を出すときに顧客テーブルとJOINしなくても済むので、読み取り速度が向上するケースがある。

集計処理が楽になる

必要な情報が1テーブルにまとまっていると、SUMやCOUNTなどの集計処理をシンプルに書ける。
特に帳票系のシステムでは、非正規化された方がSQLがスッキリし、実装工数も減らせる。

可視化やアウトプット用途に適している

請求書テーブルに「顧客名」を持たせておけば、請求書を生成するときに顧客テーブルと結合する必要がない。
ワンショットで帳票が作れるので、パフォーマンス的にも運用的にも楽になる。

正規化と非正規化の使い分け

正規化と非正規化は「どちらが正しいか」ではなく、「どのような場面だからどっちがいい」で決める。

正規化すべき場面

更新が多く、一貫性を保つことが重要なデータは正規化しておくべき。

  • 更新頻度が高いデータ
     情報が頻繁に変わるなら、冗長に持たない方がミスや不整合を防げる。
  • 整合性が重要なマスタ系
     代表的なのは顧客、商品、契約条件など。
    もし冗長に持ってしまうと、1か所を更新し忘れただけでデータが食い違ってしまう。

非正規化すべき場面

一方で、参照や集計が中心で「読み取り性能」や「過去の状態保持」が求められるデータは、非正規化した方がメリットが大きい。

  • 読み取り・集計が圧倒的に多いデータ
     請求書や売上レポート、ダッシュボード用スナップショットなど。
    JOINを減らし、SQLをシンプルにできる。

まとめ

正規化が「正しい」とされると思っていましたが、実務では非正規化も重要なことがあることを学びました。
特にSaaSや帳票システムでは、「過去を正しく再現するための冗長性」が重要になると実感しました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?