回 5-1 道 5 データベースと分散
データベース の 正規化 は、同じ事実を 1 か所にだけ書くように表を分ける設計です。同じ値が 2 か所にあると、1 か所だけ直して食い違う更新の異常、注文が無いと商品を登録できない挿入の異常、注文を消すと商品まで消える削除の異常が起きます。第 1〜第 3 正規形の順に表を分けるとこの 3 つ は起きなくなりますが、読むたびに表を結合する手間が増えます。
同じ値が 2 か所にあると何が壊れるかを、更新・挿入・削除の 3 つ の異常に切り分けられるようになります。
文 ゆめさくコード編集部 公開 2026年10月27日 更新 2026年10月27日 出典を確かめた日 2026年10月27日
同じ 住所を 3 枚の 注文票に 書くと、 何が困るのか 引っ越しのときに 1 枚 だけ直すと、同じ人の住所が 2 つ になって、どちらが正しいか分からなくなります。同じ値を 2 か所以上に書くと、直し漏れが食い違いになって残ります。
データベース の 正規化 (せいきか) は、この食い違いを起こさないために、同じ事実を 1 か所にだけ書くように表を分ける設計です。データを入れ始める前に、表の分け方として決めておきます。
ふつうの Web のサービスでは、商品、注文、会員といった値を、行と列の表 ( テーブル ) に入れておきます。表を 1 枚 にまとめると作るのは楽ですが、同じ商品の名前が注文の数だけ並びます。
この回では、注文の表を例に、同じ値が 2 か所にあると何が壊れるかを Python の表で実際に起こします。そのあと第 1、第 2、第 3 正規形の順に表を分け、同じ操作をしても壊れなくなることを確かめます。
上の図は住所録の例です。住所を住所録に 1 回 だけ書き、注文票は顧客の番号で指せば、直す場所は 1 つ で済みます。
正規化は どう 表を 分けるのか 正規化 は、「この列の値は、どの列が決まれば決まるのか」を見て、決まり方が違う列を別の表へ移す作業です。移したあとは、番号 (キー) で表どうしを指し合います。
同じ 値が 2 か所に あると 起きる 3 つの異常 1 枚 の表に、注文と商品と分類をまとめて書いたとします。
注文 商品 名前 分類 分類名 個数 1 P1 ノートPC C1 パソコン 1 1 P2 マウス C2 周辺機器 2 2 P1 ノートPC C1 パソコン 1 3 P3 キーボード C2 周辺機器 1
ノートPC という名前と、パソコン という分類名が 2 行 ずつ書かれています。この表では次の 3 つ の異常 (いじょう) が起きます。
異常 何をすると 何が壊れるか 更新の異常 分類名を 1 行だけ直す 同じ 分類に 名前が 2 つできる 挿入の異常 まだ 売れていない 商品を足す 注文の 番号が 無いので 行を作れない 削除の異常 注文 3 を消す キーボード という 商品の 情報まで消える
3 つ とも原因は同じで、寿命が違う事実を 1 つ の行に混ぜたことです。注文は毎日増えて消えますが、商品や分類は注文と関係なく長く残ります。
主キーと関数従属 主キー (しゅキー) は、表の 1 行 を 1 つ に決める列、または列の組です。上の表では、注文 1 に商品が 2 つ あるので注文だけでは行が決まらず、(注文, 商品) の組が主キーになります。
関数従属 (かんすうじゅうぞく) は、「列 X の値が決まれば、列 Y の値が 1 つ に決まる」という関係です。商品が P1 なら名前は必ずノートPC なので、名前は商品に従属します。正規化は、この従属の向きを見て表を分けます。
第 1 正規形 1 マスに 1 つの値 第 1 正規形は、表のどのマスにも値が 1 つ だけ入っている形です。注文 1 の商品の欄に「ノートPC,マウス」と 2 つ を書いた表は、まだ第 1 正規形ではありません (非正規形と呼びます)。
1 マスに 2 つ あると、「マウスを買った注文」を探すときに文字を切り分けて調べる手間が要ります。1 行 1 商品に分ければ、等しいかを比べるだけで探せます。
第 2 正規形 主キーの 一部だけで 決まる列を出す 第 2 正規形は、第 1 正規形で、しかも主キーの一部だけで決まる列が無い形です。上の表の主キーは (注文, 商品) ですが、名前と分類は商品だけで決まります。この「主キーの一部への従属」を部分関数従属と呼びます。
名前と分類を商品の表へ移すと、注文の明細の表に残るのは、(注文, 商品) の組で初めて決まる個数だけになります。
第 3 正規形 キーでない 列を 経由する 従属を出す 第 3 正規形は、第 2 正規形で、しかもキーでない列が、別のキーでない列を経由して主キーから決まる関係が無い形です。商品の表では、商品が分類を決め、分類が分類名を決めます。商品から分類名が、分類を経由して決まる関係を推移的関数従属と呼びます。
分類名を分類の表へ移すと、分類名を書く場所は 1 か所になります。ここまで分けた表は次の 3 枚 です。
表 主キー 残る列 明細 (注文, 商品) 個数 商品 商品 名前、分類 分類 分類 分類名
下の図で、乱れた表に手順 1 から 3 を順に当てると、表が何枚に割れるかを確かめられます。
動かして確かめる 1 本 目は、第 1 正規形にする前の表です。1 マスに 2 つ 入った商品の欄を切り分け、1 行 1 商品にします。
動かす 1 マスに 1 つの値にする
実行すると、次の通りに出ます
(1, 'ノートPC')
(1, 'マウス')
(2, 'ノートPC')
マウス [1]2 行 だった表が 3 行 になり、どのマスも値が 1 つ になりました。マウスを買った注文は、等しいかを比べるだけで 1 だと分かります。
2 本 目は、上の 4 行 の表 (第 1 正規形だが第 2 正規形ではない表) で、3 つ の異常を順に起こします。
動かす 1 枚の表で 3 つの異常を起こす
実行すると、次の通りに出ます
更新 ['PC', 'パソコン']
挿入 False
削除 False
行の数 3分類 C1 の名前を 1 行 目だけ PC に直すと、C1 には PC と パソコン の 2 つ の名前ができました。どちらが正しいかは、表を見ても分かりません。
まだ注文の無いタブレットは、 主キー の注文が欠けるので入りませんでした (False)。注文 3 を消すと行は 3 行 になり、P3 のキーボードはどの行にも残りません (False)。消したかったのは注文だけでした。
3 本 目は、第 3 正規形まで分けた 3 枚 の表で、同じ 3 つ の操作をします。
動かす 分けた表で同じ操作をする
実行すると、次の通りに出ます
更新 ['PC']
挿入 True
削除 キーボード
明細の数 3
(1, 'ノートPC', 'PC', 1)
(1, 'マウス', '周辺機器', 2)
(2, 'ノートPC', 'PC', 1)分類名は分類の表に 1 か所しか無いので、直すのも 1 か所で、結合して戻した表でもノートPC の分類名は PC の 1 つ だけでした。
タブレットは注文が無くても商品の表に入り (True)、注文 3 の明細を消してもキーボードは商品の表に残りました。最後の 3 行 は、view() で 3 枚 の表を結合して 1 枚 に戻した姿です。
分けすぎると 何が 起きるのか 正規化 した表は、読むたびに別の表を引き合わせる (結合する) 手間がかかります。分ける表が増えるほど、1 行 を読むために引く表も増えます。
4 本 目は、明細 100 行 を分類名つきで読むときに、別の表を何回引くかを数えます。後半は、その手間を省くために注文の合計をわざと注文の側に持ち (非正規化)、1 か所だけ直し漏れを起こします。
動かす 結合の手間と、わざと崩した合計
実行すると、次の通りに出ます
明細 100
引いた回数 200
持った合計 98000
数え直し 102000明細 100 行 を読むのに、商品の表と分類の表を 1 回 ずつ、合わせて 200 回 引きました。1 枚 の表なら、名前も分類名も同じ行にあるので別の表を引きません。本物の データベース では、結合は索引 (さくいん) などで速くできますが、表が増えるほど読む手間が増える向きは変わりません。
後半では、合計を注文の側に持ったので、明細を足すたびに合計も直す必要があります。2 つ 目の明細で合計を直し忘れると、持った合計は 98000、明細から数え直すと 102000 になり、同じ注文に 2 つ の合計ができました。わざと崩すと、読みは速くなる代わりに、この回の最初の更新の異常が戻ってきます。
上の図は、会員の表に注文の合計を持たせる例です。注文の件数を増やすと、毎回数える側は読む行が増え、合計を持つ側は書く先が 1 つ 増えます。
非正規化 (ひせいきか) を選ぶのは、読みがとても多く、結合が遅いと測って分かったときです。選ぶなら、合計を直す処理を 1 か所にまとめ、ときどき明細から数え直して食い違いが無いかを確かめます。
同じ値に 見えて、 別の 事実のもの すべての重なりが悪いわけではありません。注文の明細に「買った時の値段」を書くのは、商品の今の値段とは別の事実なので、重複ではありません。
動かす 値段を商品の表だけに置くと
実行すると、次の通りに出ます
値上げ前 98000
値上げ後 108000
残した値段 98000値段を商品の表だけに置くと、値上げした瞬間に先月の注文の合計まで 98000 から 108000 に変わりました。明細に買った時の値段を残せば、先月の注文は 98000 のままです。正規化で消すのは「同じ事実の写し」で、「時点の違う別の事実」は残します。
正規化できているかを 仕事で どう 確かめるのか 仕事では、表を作る前に「この列は何が決まれば決まるか」を 1 列ずつ問い、主キー以外で決まる列が無いかを確かめます。
表ごとに 主キー を書き出す。複数の列の組なら、組のどの部分で決まる列があるかを見る キーでない列から決まる列 (分類から分類名) が無いかを見る 同じ名前や住所を書く列が、2 つ 以上の表に無いかを見る わざと残した重なり (合計、買った時の値段) には、なぜ残したかを書き残す すでにデータがあるなら、列 X の同じ値に、列 Y の違う値が混ざっていないかを数えると、従属を手元で確かめられます。
動かす 列が列を決めるかを数える
実行すると、次の通りに出ます
商品 -> 名前 True
商品 -> 分類 True
分類 -> 分類名 True
注文 -> 名前 False
注文 -> 個数 False商品は名前と分類を決め、分類は分類名を決めました。注文だけでは名前も個数も決まりません。主キー (注文, 商品) の一部の商品が名前を決めるので第 2 正規形ではなく、キーでない分類が分類名を決めるので第 3 正規形でもない、と読めます。
ただし、今あるデータで True でも、将来の行で崩れることがあります。数えた結果は手がかりで、決まり方は業務の約束 (1 つ の商品に名前は 1 つ ) から決めます。
分けた表は、 SQL では結合 ( JOIN ) で 1 枚 に戻して読みます。上の 3 本 目の view() と同じことを書くと、次の形になります。
分けた表を結合して読む
SELECT l.order_id, p.name,
c.name, l.qty
FROM lines l
JOIN products p
ON p.id = l.product_id
JOIN categories c
ON c.id = p.category_id;関わる実例 正規化 の不備そのものを原因とした、会社の公表された事後報告は、この回では確かめられませんでした。代わりに、正規化という言葉と考え方がどこから来たかを、元の論文で読みます。
正規化は どこから 来たか、 E. F. Codd の 1970 年の論文 1970年 6月 、IBM の研究所 (カリフォルニア州サンノゼ) の E. F. Codd が、Communications of the ACM の第 13 巻 6 号に「A Relational Model of Data for Large Shared Data Banks」を出しました。データを表 (関係) として扱う、今の関係データベースの元になった論文です。ACM の文献の頁によると、この論文は 1969年 8月 19日 の IBM の研究報告 RJ599 を直した版です。
論文の要旨は、大きなデータバンクを使う人を、データが機械の中でどう並んでいるかを知らなければならない状態から守るべきだ、と書き出しています。
1.4 節 「NORMAL FORM」で、Codd は、値の中にさらに表を抱えた「単純でない定義域」を取り除く手順を normalization (正規化) と名付けました。例は社員の表で、職歴と子どもが社員の中に入れ子になり、給与の履歴が職歴の中に入っています。親の 主キー (社員の番号) を子の表へ写して入れ子をほどき、社員、職歴、給与の履歴、子どもの 4 枚 に分けます。1 マスに 1 つ の値にする、この回の 1 本 目と同じ向きの作業です。
同じ節は「正規化の種類の操作はほかにもあるが、この論文では扱わない」と書いています。ACM の文献の頁によると、関数従属と最初の 3 つ の正規形を持ち込んだのは、1972 年 の「Further Normalization of the Data Base Relational Model」です。
2.3 節 「CONSISTENCY」は、重なり (redundancy) を持つ表の組では食い違い (inconsistency) が起き得るとし、挿入、削除、キーの更新のたびに食い違いを調べるやり方を挙げています。続けて、その調べはこれらの操作を遅くすると書いています。同じ値を 2 か所に置くと、食い違いを防ぐ手間がどこかに必要になる、というこの回の話は、論文の時点で書かれていました。
Codd は 1981 年 に ACM のチューリング賞を受けました。授賞の理由は「データベース管理システムの理論と実践への、基本的で継続的な貢献」です。
崩れた前提は「使う人はデータの並べ方を知っている」です。並べ方に頼らず、同じ事実を 1 か所に置いて表を番号で指し合う考え方が、ここから始まりました。
出典は 論文の写し (ペンシルベニア大学の講義の頁に置かれた PDF) 、Codd の紹介 (ACM A.M. Turing Award) 、Codd の文献の頁 (ACM A.M. Turing Award) です。
よくある問い どこまで 正規化すれば よいのですか この回では、第 3 正規形までを 1 つ の目安にしています。第 3 正規形まで分けると、キーでない列を経由して決まる列が無くなり、更新・挿入・削除の 3 つ の異常は、この回の例では起きなくなりました。そこから先は、読みの速さと書きの手間を測って、わざと崩すかを決めます。
非正規化は してはいけないのですか してよい場面があります。読みがとても多く、結合が遅いと測って分かったときに、合計などを写して持ちます。その代わり、写した値を直す処理を 1 か所にまとめ、ときどき元から数え直して食い違いを確かめます。
ボイス・ コッド正規形は 第 3 正規形と 何が 違うのですか ボイス・コッド正規形は、第 3 正規形より厳しく、「ほかの列を決める列は、どれも候補キー (行を 1 つ に決められる列の組) でなければならない」とする形です。第 3 正規形でも、候補キーの一部の列が、候補キーでない列から決まる珍しい表では、この条件を満たさないことがあります。さらに先に第 4、第 5 正規形もありますが、この回では扱いません。
正規化すると 必ず 遅くなるのですか 読むときに結合する手間は増えますが、遅いかどうかは測って決めます。書くときは直す場所が 1 か所で済むので、書きの多い表ではむしろ手間が減ります。4 本 目のように、読む手間と書く手間は反対に動きます。
確認クイズ 答えだと 思う 選択肢を 押すと、 その場で 正誤と 理由が 開きます。 4 問すべてに 正しく 答えると、 この 回は 修了で、 石が 緑に 変わります (この 端末の ブラウザに 残ります)。 間違えた 問いは、 あとから 解き直せます。
1 問目
1 枚 の注文の表で、注文 3 を消したら、その注文でしか買われていなかった商品の名前まで表から消えました。これは何と呼ぶ異常ですか。
2 問目
このコードを動かすと何が出ますか。
写しを数える
rows = [("P1", "マウス"),
("P1", "マウス"),
("P2", "キーボード")]
d = dict(rows)
print(len(rows), len(d))3 問目
主キー が (注文, 商品) の明細の表に、商品だけで決まる商品名の列があります。この表が満たしていない正規形はどれですか。
ア 第 1 正規形 イ 非正規形 ウ どれも 満たしている エ 第 2 正規形 4 問目
注文の明細に、商品の今の値段とは別に「買った時の値段」の列を置きました。この列について正しいのはどれですか。
ア 時点の 違う 別の 事実なので、 残してよい イ 商品の 値段の 写しなので、必ず消す ウ 第 1 正規形を 満たさなくなる エ 値上げの たびに、 明細の 値段も全部直す 説明課題 同じ値を 2 か所に置くと何が壊れるかを、「更新」「挿入」「削除」「第 3 正規形」という言葉を使って、注文の表の例で 3〜4 文で説明してください。書いたら、下の模範解答を開いて比べてください。
あなたの説明
模範解答 模範解答を開く 自分の 説明を 書いてから 開いて、 比べてください。
注文と商品と分類を 1 枚 の表に書くと、分類名が注文の数だけ並び、1 行 だけ直すと同じ分類に名前が 2 つ できる更新の異常が起きる。まだ売れていない商品は注文の番号が無いので行を作れず (挿入の異常)、ある商品を買った最後の注文を消すと商品の情報まで消える (削除の異常)。原因は、寿命が違う事実を同じ行に混ぜたことで、明細、商品、分類の 3 枚 に分けて第 3 正規形にすると、分類名は 1 か所だけになり 3 つ とも起きなくなる。その代わり読むたびに結合が要るので、わざと合計などを写すなら、直し漏れを数え直しで確かめる。
新しい 機能で 表や列を 足すたびに、 その 値が ほかの 表に もう 書いてないかを 問えると、 食い 違いの 直しに 追われる 仕事を 前もって 減らせます。
もっと深く この 回の 続きを、 ゆめさくの コースの 章や 道具で 深められます。 頁の 中の 確認クイズに 答えた あと、 手を 動かす量を 増や したい ときに 使ってください。
一次資料 どれも 2026年 10月 27日 に開いて、題と中身を確かめました。