Strukturiere deine Schemata von der 1NF bis zur 3NF, um Anomalien zu beseitigen, und wisse, wann du bewusst denormalisierst.
Diese Lektion in Kodokon öffnenEin schlechtes Schema kostet dich über Jahre. Die Normalisierung verfolgt ein einziges Ziel: dass jede Tatsache nur einmal gespeichert wird, um drei Anomalien zu beseitigen: die Änderungsanomalie (eine E-Mail an zehn Stellen ändern), die Einfügeanomalie (kein Produkt ohne eine Bestellung hinzufügen zu können) und die Löschanomalie (das Löschen der letzten Bestellung löscht die Kundin oder den Kunden). Sieh dir dieses absichtlich verpfuschte Schema an.
CREATE TABLE bad_orders (
id INTEGER PRIMARY KEY,
customer_name TEXT,
customer_email TEXT,
product_names TEXT,
total REAL
);
INSERT INTO bad_orders
(customer_name, customer_email,
product_names, total)
VALUES
('Alice', 'alice@mail.com',
'keyboard,mouse', 74.0),
('Alice', 'alice@mail.co',
'monitor', 199.0);Die ersten drei Normalformen in der Praxis. 1NF: atomare Werte - product_names = 'keyboard,mouse' verletzt sie und macht jedes WHERE oder JOIN auf Produkte unpraktikabel. 2NF (zusammengesetzter Schlüssel): Jede Spalte hängt vom gesamten Schlüssel ab - den Katalogpreis eines Produkts in einer durch (Bestellung, Produkt) identifizierten Bestellzeile zu speichern verletzt sie, weil der Preis nur vom Produkt abhängt. 3NF: Keine Nichtschlüsselspalte hängt von einer anderen Nichtschlüsselspalte ab - customer_email, das von customer_name abhängt, verletzt sie; daher das Duplikat alice@mail.co. Hier ist das korrigierte Schema.
CREATE TABLE customers (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE
);
CREATE TABLE products (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
price REAL NOT NULL
);
CREATE TABLE purchases (
id INTEGER PRIMARY KEY,
customer_id INTEGER NOT NULL
REFERENCES customers(id)
);
CREATE TABLE purchase_items (
purchase_id INTEGER NOT NULL
REFERENCES purchases(id),
product_id INTEGER NOT NULL
REFERENCES products(id),
quantity INTEGER NOT NULL,
PRIMARY KEY (purchase_id, product_id)
);PRAGMA foreign_keys = ON;
INSERT INTO customers (name, email)
VALUES ('Alice', 'alice@mail.com');
INSERT INTO products (name, price)
VALUES ('keyboard', 49.0), ('mouse', 25.0);
INSERT INTO purchases (customer_id) VALUES (1);
INSERT INTO purchase_items
(purchase_id, product_id, quantity)
VALUES (1, 1, 1), (1, 2, 1);
SELECT c.name, p.name AS product,
i.quantity, p.price
FROM purchase_items AS i
JOIN purchases AS pu ON pu.id = i.purchase_id
JOIN customers AS c ON c.id = pu.customer_id
JOIN products AS p ON p.id = i.product_id;Wann solltest du also denormalisieren? Wenn die Lesevorgänge zum gemessenen Engpass werden: Joins über fünf Tabellen auf einem kritischen Bildschirm, ein bei jedem Rendern neu berechnetes Aggregat. Die ehrlichen Muster: eine Cache-Spalte (purchases.total, zum Bestellzeitpunkt eingefroren - und das zu Recht: Der gezahlte Preis ist eine historische Tatsache, verschieden vom Katalogpreis), ein per Trigger gepflegter Zähler oder eine im Batch neu aufgebaute Reporting-Tabelle. Der Preis dafür: Jede Kopie kann abweichen, und nun garantiert dein Code die Konsistenz, nicht mehr die Engine.