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?

【初心者メモ】DB設計の正規化を第1〜第5正規形まで、注文テーブルで整理してみた

0
Last updated at Posted at 2026-08-26

はじめに

初めてDB設計を担当することになり、まず「そもそもDB設計とは何をするのか」というところから勉強を始めました。その中で必ず出てくるのが「正規化」で、「1次正規化・2次正規化…」という言葉に最初はかなり戸惑いました。正直、最初は「正規化」が何を指すのかもよく分かっていませんでした。

調べていくと、これは第1正規形・第2正規形…とテーブルを段階的に整えていく作業のことでした。第1〜第2あたりまでは何とか飲み込めたのですが、第3正規形から先がずっとふわっとしていたので、思い切って第1〜第5正規形まで通しで自分の理解を整理してみることにしました。

第1〜第3正規形は「注文テーブル」を1つ用意して、それを段階的に直していく形で説明します。第4・第5正規形は注文テーブルだと問題が自然に出てこないので、その部分だけ専用の例に切り替えます(理由も本文で説明します)。

初心者の学習メモです。特に第4・第5正規形は間違えやすいところなので、誤りがあればご指摘ください。

対象読者

  • これからDB設計を始める人
  • 第3正規形くらいまでは聞いたことがあるが、その先が曖昧な人
  • 「結局どこまでやればいいの?」が気になる人

そもそも正規化とは

データの重複や矛盾が起きないように、テーブルを適切に分割していく作業です。1つの大きな表にすべてを詰め込むと、同じ情報があちこちにコピーされ、片方だけ直し忘れて食い違う、といった事故が起きます。それを段階的に防いでいきます。

段階には第1〜第5正規形(と、第3と第4の間にBCNF)があり、数字が大きいほど厳しくなります。


第1正規形(1NF):1つのセルに複数の値を入れない

解決すること:繰り返し項目・複数値を1セルに詰め込むのをやめる。

こんな注文テーブルがあるとします。1回の注文に複数商品が入っていて、1セルに詰め込まれています。

違反している例

注文ID 顧客名 商品 数量
1 田中 りんご, みかん 2, 3
2 佐藤 ばなな 1

商品 のセルに複数値が入っている(数量 も同様)のが違反です。これだと「みかんは何件売れた?」を集計できませんし、どの商品がいくつなのかも対応が取りづらいです。

1NFにした後(1行1商品に分解)

注文ID 顧客名 商品 数量
1 田中 りんご 2
1 田中 みかん 3
2 佐藤 ばなな 1

キーワード:1セル1値。


第2正規形(2NF):主キーの一部だけで決まる項目を分ける

解決すること:主キーが複合キー(複数列)のとき、その一部の列だけで決まってしまう項目を分離する。

前提として、これは主キーが複数列の組み合わせ(複合キー)になっているときに問題になる話です。

上の表の主キーを (注文ID, 商品) の複合キーだとします。ここで 顧客名 を見ると、これは 商品 とは関係なく 注文ID だけで決まります。主キーの一部(注文ID)だけで決まる項目がある——これが部分関数従属で、2NF違反です。

違反している状態顧客名注文ID だけに依存しているのに、(注文ID, 商品) の表に同居している。→ 同じ注文の顧客名が行数ぶん重複する。

2NFにした後(注文の情報と、注文明細を分ける)

注文テーブル

注文ID 顧客名
1 田中
2 佐藤

注文明細テーブル

注文ID 商品 数量
1 りんご 2
1 みかん 3
2 ばなな 1

キーワード:部分関数従属の除去(複合キーの一部にだけ依存する項目を分離)。


第3正規形(3NF):主キー以外の項目に依存する項目を分ける

解決すること:主キーではなく、別の項目を経由して決まる項目を分離する。

注文テーブルに顧客の情報を足してみます。主キーは 注文ID です。

違反している例

注文ID 顧客名 顧客ランク 送料区分
1 田中 ゴールド 送料無料
2 佐藤 シルバー 通常送料
3 田中 ゴールド 送料無料

この表をよく見ると、依存関係が2段になっています。

  • 顧客名 が決まると 顧客ランク が決まる(田中さんはゴールド)
  • 顧客ランク が決まると 送料区分 が決まる(ゴールドは送料無料)

つまり 顧客ランク送料区分 は、主キー 注文ID そのものではなく、顧客名 を経由して間接的に決まっています。この「キー以外の項目を経由して決まる」状態が推移的関数従属で、3NF違反です。田中さんのランクが変われば、田中さんの注文の行すべてを直す必要が出てしまいます。

3NFにした後(顧客を独立したテーブルに切り出す)

切り出すときに、顧客を一意に識別するための 顧客ID を新しく振ります。

注文テーブル

注文ID 顧客ID
1 C01
2 C02
3 C01

顧客テーブル

顧客ID 顧客名 顧客ランク 送料区分
C01 田中 ゴールド 送料無料
C02 佐藤 シルバー 通常送料

これで顧客ランクや送料区分の変更は、顧客テーブルの1行を直すだけで済みます。

厳密には、この顧客テーブルにはまだ 顧客ランク → 送料区分 という依存が残っています。より徹底するならランクと送料区分をさらに別テーブルに分けますが、実務ではここまでで止めることも多いです。まずは「キーを経由しない依存を切り出す」という考え方をつかむのが目的です。

キーワード:推移的関数従属の除去(キー以外の項目に依存する項目を分離)。

実務ではここがゴールになることがほとんどです。多くのテーブルは3NFまでやれば十分整います。


ここから先(BCNF・4NF・5NF)について

第3正規形までは1つの注文例で説明できましたが、ここから先は注文テーブルだと問題が自然に発生しません。BCNF以降は「候補キーが複雑に絡む」「多値従属」「結合従属」といった特殊な状況で初めて出てくるためです。

なので、ここからは各正規形ごとに、その問題が起きる最小の専用例で説明します。そして正直に言うと、この3つは実務で出番が少なく、「こういうものがある」と知っておくレベルです。


ボイス・コッド正規形(BCNF):3NFの取りこぼしを直す

3NFでも、候補キーが絡む特殊なケースで矛盾が残ることがあります。BCNFは「すべての関数従属について、決める側(左辺)が候補キー(その値が決まれば行が一意に定まる列の組み合わせ)であること」を求める、3NFを少し厳しくした形です。

例:塾の受講を管理する表を考えます。ルールはこうです。

  • 1人の生徒は、1つの科目につき1人の教師に習う(だから (生徒, 科目) で行が一意に決まる=主キー)
  • 各教師は1科目だけを担当する(だから 教師 → 科目 が成り立つ)
生徒 科目 教師
Aさん 数学 山田
Bさん 数学 山田
Aさん 英語 鈴木

この表は3NFは満たしています(主キー以外の非キー属性が推移的に依存する、という状態ではない)。しかし 教師 → 科目 という従属があり、その左辺の 教師 は候補キーではありません。「候補キーでないものが、他の項目を決めている」——これがBCNF違反です。実際、山田先生の担当科目が変われば、山田先生の行すべてを直す必要が出ます。

BCNFにした後教師 → 科目 を別テーブルに切り出します。

教師テーブル教師(主キー), 科目
受講テーブル生徒, 教師(この2つで元の情報を復元できる)

キーワード:候補キーでない項目が他項目を決めている状態の除去。


第4正規形(4NF):無関係な多対多を1つの表に同居させない

多値従属という状況で起きます。1つのキーに対して、互いに無関係な(独立した)複数の項目が、それぞれ多対多でぶら下がっているケースです。ここで「無関係であること」がこの正規形のいちばんの肝です。

例:ある社員が持つ「スキル」と「趣味」を1つの表にしたとします。スキルと趣味は互いに何の関係もありません。

違反している例

社員 スキル 趣味
田中 Java 釣り
田中 Java 登山
田中 Python 釣り
田中 Python 登山

田中さんのスキル2つ × 趣味2つで、無関係なものの全組み合わせ4行ができています。スキルを1つ足すと、趣味の数だけ行が増えてしまう。この「無関係な項目同士のかけ算」で行が膨らむのが、多値従属による4NF違反です。

4NFにした後(無関係なものは別テーブルに)

スキルテーブル社員, スキル
趣味テーブル社員, 趣味

こうすれば、スキルを足しても趣味の行は増えません。

間違えやすいポイント
「無関係な2つの多値項目が同居しているとき」だけが4NFの話です。たとえば「スキル」と「そのスキルの資格」のように、片方がもう片方に紐づく(=無関係でない)場合は、ただの1対多であって4NFの問題ではありません。"互いに無関係な多値項目の同居"かどうか、で線を引きます。

キーワード:多値従属の除去(無関係な多対多を分離する)。


第5正規形(5NF):3つに分解して結合で元に戻せるなら分解する

結合従属という、正規化の中でいちばん特殊で、いちばん誤解されやすい状況です。ざっくり言うと、3つ以上の要素が絡む関係を、2つずつのペアの表に分解し、それらを結合すると元の表がちょうど復元できる——そういう場合に、分解しておくのが5NFです。

例:「営業担当・商品・仕入先」の3者の関係を考えます。ここで、次のような循環したルールが成り立つ場合だけを扱います。

担当がその商品を扱っていて、かつ その商品をその仕入先が供給していて、かつ その担当がその仕入先と取引がある。この3つがすべて揃ったときだけ、その(担当・商品・仕入先)の組み合わせが成立する。

このルールがあるとき、1枚の3列表で持つより、次の3つのペア表に分解できます。

  • 担当 × 商品
  • 商品 × 仕入先
  • 担当 × 仕入先

この3つを結合すると、元の表がちょうど復元できます(情報が増えも減りもしない)。1枚表のままだと、ルール上ありえない組み合わせを防げず冗長も出るため、分解しておくのが5NFです。

間違えやすいポイント(最重要)
これは「担当・商品・仕入先を、とにかく3つに割ればいい」という話ではありません。上のような循環したルールが成り立つときだけ、3分解して結合しても元に戻ります。その条件が無いのに機械的に3分解すると、結合したときに元の表に無かった余計な行が生まれてしまい(=復元に失敗し)、むしろデータが壊れます。「無条件に3分解してよい」と書いている解説を時々見かけますが、それは誤りです。ここが5NFで一番つまずくところでした。

キーワード:結合従属の除去(3分解して結合で正しく復元できるときだけ分解する)。

5NFは理論的な色が濃く、上のような循環ルールが成り立つ場面自体がまれなので、実務で意図的に適用することはほとんどありません。自分も「こういう概念がある」という理解にとどめています。


まとめ表(各正規形の早見表)

正規形 解決する問題 キーワード 実務での頻度
1NF 繰り返し・複数値 1セル1値 ほぼ必須
2NF 部分関数従属 複合キーの一部への依存 ほぼ必須
3NF 推移的関数従属 キー以外への依存 実務のゴール
BCNF 3NFの取りこぼし 候補キーが絡む従属 たまに
4NF 多値従属 無関係な多対多の同居 まれ
5NF 結合従属 条件付きで3分解できる ほぼ理論

正規化にはデメリットもある(非正規化の話)

ここまで「正規化しよう」という話をしてきましたが、勉強していて「じゃあ正規化はいいことだらけなのか?」という疑問が湧きました。調べてみると、正規化には代償もあることが分かりました。

正規化はテーブルを分割していく作業なので、その裏返しとして次のようなデメリットが出ます。

  • 結合(JOIN)が必要になる:1つの表で済んでいたものが複数に分かれるので、「注文と顧客名を一緒に見たい」だけでもテーブルをつなぎ直す必要が出ます。分割が進むほど、1つの画面を作るのに何個も結合することになります。
  • データが大量だと重くなる:巨大なテーブル同士を結合すると、(インデックスが無ければ)処理が重くなります。分けた分だけ、読むときに繋ぐコストがかかります。
  • 集計を毎回やり直す:合計や件数などを、分割された生データから都度計算することになります。

マスタとトランザクションで出方が違う

面白いのは、このデメリットがどのデータでも等しく出るわけではないことです。テーブルは大きく2種類に分けられます。

  • マスタ(顧客・商品など、あまり増減しないデータ):件数が少ないので、分割しても結合は軽い。→ デメリットはほぼ出ない。しっかり正規化してOK。
  • トランザクション(注文・履歴など、どんどん増えるデータ):件数が膨大になる。→ 結合や集計が重くなるのは主にこちら。

つまり「正規化で重くなる」問題は、増え続けるトランザクション系で顕在化する、という切り分けができます。

あえて崩す:非正規化

デメリットが実際に問題になったとき、あえて正規化を崩して速さを優先する選択肢があります。これを非正規化(denormalization)と呼びます。たとえば「毎回JOINするのが重いから、注文テーブルに顧客名をあえてコピーして持つ」といった対応です。

非正規化は「速さ」と引き換えに、正規化で防いだはずの"重複と矛盾"のリスクを引き受けることです。顧客名をコピーして持てば、名前が変わったときにコピーした全部を直す必要が出てきます。だから安易にやるものではありません。

自分なりの結論

いろいろ調べて、順番はこう理解しました。

まず正規化する。デメリットが実際に問題になって初めて、必要な箇所だけ非正規化する。

最初から「重くなりそうだから崩しておこう」はやらない、という点が大事だと感じました。正規化してきちんと作っておけば、後から崩すのは選べます。でも最初から崩してしまうと、あとで正しい形に戻すのは大変です。

おわりに

「DB設計とは何か」から入って、その一部として正規化に出会った自分ですが、第1〜第5正規形まで通して整理してみて、一番の学びは 「全部やればいいわけではない」 という点でした。実務では第3正規形(必要に応じてBCNF)までで十分整うことがほとんどで、4NF・5NFは「そういう概念がある」と知っておくレベル、という温度感がつかめました。

数字を上げること自体が目的ではなく、重複と矛盾をなくすための手段、という理解で使い分けていきたいです。同じように「正規化・1次正規化って何?」から入った人の、地図がわりになれば嬉しいです。

参考

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?