12
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

正規化はパフォーマンスの敵?非正規化との付き合い方を徹底解説

12
Posted at

■ この記事はこんな人におすすめ

  • SQLを書き始めて、JOINを多用するようになってきた人
  • 「正規化って本当に正しいの?」と疑問を感じたことがある人
  • パフォーマンスチューニングに興味がある初・中級エンジニア
  • 非正規化という言葉は聞いたことあるけど、具体的にどんなものかわからない人

■ この記事で得られること

  • 正規化がパフォーマンスに与える影響が理解できます
  • 非正規化のパターンと、それぞれのトレードオフが判断できるようになります
  • 正規化と非正規化を「使い分ける」判断軸が持てるようになります

■ 参考書籍

本記事は上記書籍の5章の内容をもとに構成しています。

1. 結論

正規化は原則として正しい選択です。ただし、パフォーマンス上の限界に達したとき、非正規化は有効な「最後の手段」になります。

正規化されたテーブルは、データの整合性を保ちやすく、更新の手間も少ない。しかしJOINが増えるほど、クエリのコストは上がっていきます。非正規化はその問題を解決できる一方で、「更新コストの増大」と「データのリアルタイム性の低下」という2つのリスクを抱えます。

この記事では、具体的なSQL例を通じてその仕組みを理解していきましょう!

2. まずは下記を理解しよう!

■ ① 正規化がパフォーマンスに影響するケースを把握する

JOINの回数・種類によって、パフォーマンスへの影響度が変わります。

以下のテーブル構成を例に考えます:

会社テーブル

会社コード 会社名
C0001 A 商事
C0002 B 化学
C0003 C 建設

社員テーブル

会社コード 社員ID 社員名 年齢 部署コード
C0001 E0001 加藤 40 D01
C0001 E0002 藤本 32 D02
C0002 E0002 田島 25 D01

部署テーブル

部署コード 部署名
D01 開発
D02 人事
D03 営業

■ ② パターン別にJOINのコストを比較する 🔍

【パターン1】テーブル2つを内部結合

-- 会社名と社員名を取得
SELECT 会社.会社名, 社員.社員名
FROM 社員
INNER JOIN 会社 ON 会社.会社コード = 社員.会社コード
WHERE 社員.社員名 = '田島';

【パターン2】テーブル3つを内部結合

-- 会社名・社員名・部署名を取得
SELECT 会社.会社名, 社員.社員名, 部署.部署名
FROM 社員
INNER JOIN 会社 ON 会社.会社コード = 社員.会社コード
INNER JOIN 部署 ON 社員.部署コード = 部署.部署コード
WHERE 社員.社員名 = '田島';

【パターン3】外部結合で集計

-- 会社ごとの社員数を集計(社員がいない会社もNULLで表示)
SELECT 会社.会社コード, COUNT(社員.社員名) AS 社員数
FROM 会社
LEFT OUTER JOIN 社員 ON 社員.会社コード = 会社.会社コード
GROUP BY 会社.会社コード;

✅ パターン1〜3は、適切なインデックスが設定されていれば、パフォーマンス差はほぼ誤差レベルです。

■ ③ 非正規化で結合をゼロにするパターンを知る

【パターン4】非正規化テーブル(JOINなし)

会社名・部署名を社員テーブルに持たせてしまう設計です。

会社コード 会社名 社員ID 社員名 年齢 部署コード 部署名
C0001 A 商事 E0001 加藤 40 D01 開発
C0001 A 商事 E0002 藤本 32 D02 人事
C0002 B 化学 E0002 田島 25 D01 開発
-- JOINなしで取得できる ✨
SELECT 会社名, 社員名, 部署名
FROM 社員
WHERE 社員名 = '田島';

このパターンは明らかに速いです。ただし、後述するリスクとのトレードオフがあります⚠️

■ ④ 非正規化の2パターン(実務でよく使う)を理解する

受注テーブルと受注明細テーブルを使った例で考えます。

受注テーブル

受注ID 受注日 注文者名義
0001 2026-01-05 岡野 徹
0002 2026-01-06 浜田 健一
0003 2026-01-08 石井 慶子

受注明細テーブル

受注ID 受注明細連番 商品名
0001 1 マカロン
0001 2 紅茶
0002 1 紅茶
0002 2 日本茶

📅 非正規化パターンA:明細テーブルに「受注日」を持たせる

受注日での範囲絞り込みを高速化したいとき、受注明細に受注日カラムを追加します。

受注ID 受注明細連番 商品名 受注日
0001 1 マカロン 2026-01-05
0001 2 紅茶 2026-01-05
0002 1 紅茶 2026-01-06

➡️ JOINなしで WHERE 受注日 BETWEEN '...' AND '...' が実行できます。

🔢 非正規化パターンB:受注テーブルに「商品数(集計値)」を持たせる

受注日別の集計を高速化したいとき、受注テーブルに商品数カラムを追加します。

受注ID 受注日 注文者名義 商品数
0001 2026-01-05 岡野 徹 4
0002 2026-01-06 浜田 健一 3
0003 2026-01-08 石井 慶子 1

➡️ GROUP BY不要で集計結果が即座に取れます。

■ ⑤ 非正規化の「2つのリスク」を認識する

非正規化には必ず以下のコストが伴います。導入前に必ず評価してください。

🔴 リスク1:更新パフォーマンスの低下

  • 会社名が変わった場合 → 全社員レコードの「会社名」カラムを一括更新する必要がある
  • 商品が追加・削除された場合 → 受注テーブルの「商品数」も更新が必要になる

🔴 リスク2:データのリアルタイム性の低下

  • 集計値(商品数など)を都度更新すると、DBへの書き込み負荷が増える
  • 更新頻度を下げると、集計値が実態とずれる(リアルタイム性が失われる)

3. 各項目の説明

■ なぜパターン1〜3のパフォーマンス差は誤差レベルなのか?

JOINは「インデックスさえ適切に設定されていれば」、DBエンジンが効率的に処理します。会社コードや部署コードに対してインデックスが貼られていれば、結合対象の絞り込みは非常に高速に動作します。

2〜3テーブルのJOINが問題になるのは、インデックス設計が不十分な場合や、結合結果が非常に大きくなる場合(例:数百万件同士のJOIN)です。

■ パターン4(非正規化)はなぜ速いのか?

結合処理そのものが不要になるからです。1テーブルへのシンプルなSELECTは、複数テーブルを組み合わせる処理と比べてオーバーヘッドが少なく、クエリプランも単純になります。特に読み取り頻度が非常に高く、更新が少ないケースで効果を発揮します。

■ 非正規化を採用すべき判断基準

以下の条件が揃ったとき、非正規化を検討する価値があります:

  1. ✅ 正規化+インデックス最適化を行っても、パフォーマンスが要件を満たせない
  2. ✅ 対象のデータが読み取り頻度が高く、更新頻度が低い
  3. ✅ データの不整合リスクをアプリケーション側でコントロールできる

逆に、更新が頻繁なデータに非正規化を適用すると、更新コストと不整合リスクが膨らみ、正規化以上のパフォーマンス問題を引き起こすことがあります🚨

まとめ

  • 正規化によるJOINのパフォーマンス低下は、インデックスが適切なら誤差レベル
  • 非正規化(JOINなし)は明確に速いが、トレードオフがある
  • 非正規化の2つのリスク:①更新コストの増大②リアルタイム性の低下
  • 非正規化の代表パターン:関連カラムをテーブルに持たせる / 集計値をテーブルに持たせる
  • 原則は正規化。非正規化はパフォーマンスチューニングの最後の手段 🏁

結局何をすればいいの❓

  1. 🏗️ まず正規化を徹底する(第3正規形を目指す)
  2. 🔑 インデックスを適切に設計する(結合キー・検索条件カラムを中心に)
  3. 📊 パフォーマンス計測を行う(EXPLAINでクエリプランを確認)
  4. 🔧 それでも不足なら非正規化を検討(影響範囲・更新頻度を必ず評価する)
  5. 🔒 非正規化導入後は更新処理の整合性担保を忘れずに

株式会社シンシア

株式会社xincereでは、実務未経験のエンジニアの方や学生エンジニアインターンを採用し一緒に働いています。

※ シンシアにおける働き方の様子はこちら

シンシアでは、年間100人程度の実務未経験の方が応募し技術面接を受けます。
その経験を通し、実務未経験者の方にぜひ身につけて欲しい技術力(文法)をここでは紹介していきます。

12
4
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
12
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?