3秒でわかる
重複が出ないようにテーブルを分割していくDB設計の手順。更新のときに同じ情報が食い違って残る事態を、そもそも起こらない形にします。
30秒図解
もう少し詳しく
どういうものか
正規化は、1 つの表に詰め込まれたデータを、重複が出ないように複数の表へ分けていく設計の手順です。段階があり、繰り返し項目をなくすのが第 1 正規形、主キーの一部だけで決まる列を分けるのが第 2 正規形、主キー以外の列から決まる列を分けるのが第 3 正規形です。実務では第 3 正規形まで進めるのが基本形になります。
なぜ必要か
同じ情報を複数の行に持つと、更新時に矛盾が生まれます。注文表に顧客の住所を直接書いている設計で引っ越しが起きると、過去の全行を書き換えることになり、1 行でも漏れれば「同じ顧客なのに住所が 2 種類ある」状態が残ります。どちらが正しいかはデータからは判断できません。分けて 1 か所だけに持たせておけば、直す場所が 1 行で済み、そもそも矛盾が起こりえない形になります。
具体例
分ける前(重複あり)
order_id | customer_name | customer_addr | item | price
1 | 佐藤 | 東京都... | コーヒー | 1200
2 | 佐藤 | 東京都... | 豆 | 800-- 分けたあと
CREATE TABLE customers (
id INT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
addr VARCHAR(200) NOT NULL
);
CREATE TABLE orders (
id INT PRIMARY KEY,
customer_id INT NOT NULL,
item VARCHAR(50) NOT NULL,
price INT NOT NULL,
FOREIGN KEY (customer_id) REFERENCES customers(id)
);つまずきやすいところ
分ければ分けるほど良い、と考えて表を増やしすぎると、画面を 1 枚出すのに 6 テーブルの結合が必要になり、表示が目に見えて遅くなります。そのため、参照が非常に多い箇所では意図的に重複を残す非正規化を選ぶこともあります。重要なのは、正規化してから必要な場所だけ崩す順番です。最初から崩した設計は、どこが意図的な重複なのか判別できません。もうひとつの落とし穴は、注文時点の価格を商品表から結合して表示する設計で、値上げすると過去の注文金額まで変わってしまいます。時点で確定すべき値は注文側に持たせます。
覚え方
保存は分けて、表示でつなぐ。分けた数だけ矛盾の余地が減り、つなぐ手間だけが増えます。