Normalisierung löst einige Probleme, aber manchmal schafft sie auch neue, besonders wenn es um Performance geht. Heute öffnen wir für dich das Tor zur dunklen (und manchmal auch hellen) Kunst – Denormalisierung. Ja, du darfst die Regeln der Normalisierung brechen... aber bitte mit Köpfchen!
Denormalisierung ist das Gegenteil von Normalisierung. Während Normalisierung Tabellen in einzelne logische Entitäten aufteilt, um Redundanz zu minimieren, führt Denormalisierung Daten wieder zusammen, um die Performance zu verbessern. Denormalisierung wird oft eingesetzt, wenn bei hoher Last und häufigen komplexen Abfragen das Joinen vieler Tabellen das System ausbremst.
Man kann sagen, Denormalisierung ist ein Kompromiss zwischen Datenreinheit und Geschwindigkeit der Abfragen.
Wann sollte man Denormalisierung einsetzen?
Wie bei jedem Tool ist es wichtig zu wissen, wann Denormalisierung sinnvoll ist. Sie wird in folgenden Situationen verwendet:
Häufig genutzte Abfragen werden langsam. Wenn ein System unter hoher Last immer wieder die gleichen Abfragen ausführt (zum Beispiel Reports und Aggregationen), können Joins über viele Tabellen viel Zeit kosten. Denormalisierung hilft, die Anzahl solcher Joins zu reduzieren.
Analytische Aufgaben und Statistik. In analytischen Systemen (zum Beispiel BI – Business Intelligence) braucht man oft umfangreiche Datenanalysen. In solchen Fällen beschleunigt Denormalisierung die Verarbeitung durch "vorgefertigte" Daten.
Komplexe Abfragen. Wenn du für eine Abfrage fünf, zehn oder noch mehr Tabellen joinen musst, kann das die Datenbank deutlich verlangsamen. Denormalisierung vereinfacht die Struktur der Abfragen.
Die Anzahl der Joins sprengt den gesunden Menschenverstand. Wenn du Abfragen mit 25 Tabellen im
JOINhast, ist es vielleicht Zeit, deinen Ansatz zu überdenken.
Beispiele für Denormalisierung
Beispiel 1: Online-Shop. In einer normalisierten Datenbank eines Online-Shops könnten wir folgende Tabellen haben:
kunden– Daten über Kunden.bestellungen– Infos zu Bestellungen.produkte– Daten zu Produkten.bestellpositionen– Produkte, die zu einer Bestellung gehören.
Eine Abfrage, um Informationen zu bekommen, könnte so aussehen:
SELECT
c.kundenname,
o.bestelldatum,
p.produktname,
oi.menge
FROM
kunden c
JOIN
bestellungen o ON c.kunden_id = o.kunden_id
JOIN
bestellpositionen oi ON o.bestellung_id = oi.bestellung_id
JOIN
produkte p ON oi.produkt_id = p.produkt_id
WHERE
c.kunden_id = 42;
Aber was, wenn unser Online-Shop Hunderttausende Bestellungen pro Tag verarbeitet? Diese Abfrage wird dann wegen der vielen Joins zu langsam.
Lösung: Denormalisierung.
Lass uns eine Tabelle für oft genutzte Infos anlegen:
CREATE TABLE bestell_uebersicht AS
SELECT
c.kunden_id,
c.kundenname,
o.bestellung_id,
o.bestelldatum,
p.produkt_id,
p.produktname,
oi.menge
FROM
kunden c
JOIN
bestellungen o ON c.kunden_id = o.kunden_id
JOIN
bestellpositionen oi ON o.bestellung_id = oi.bestellung_id
JOIN
produkte p ON oi.produkt_id = p.produkt_id;
Jetzt holen wir uns die Daten einfach aus bestell_uebersicht:
SELECT * FROM bestell_uebersicht WHERE kunden_id = 42;
Beispiel 2: Analytik-System. Stell dir vor, du arbeitest mit einer Datenbank für eine Firma, die Tickets für Events verkauft. Es gibt Tabellen:
events– Infos zu Events.verkaeufe– Daten zu Ticketverkäufen.
Wenn Analysten einen Report über den durchschnittlichen Umsatz pro Ticket für alle Events bauen wollen, zwingt die normalisierte Struktur dich, jedes Mal eine Aggregat-Abfrage zu machen:
SELECT
e.eventname,
AVG(s.preis) AS durchschnitt_ticketpreis
FROM
events e
JOIN
verkaeufe s ON e.event_id = s.event_id
GROUP BY
e.eventname;
Diese Abfrage kann ziemlich langsam sein, besonders wenn jede Verkaufszeile Millionen von Einträgen hat.
Lösung: Denormalisierung. Wir erstellen eine eigene Tabelle mit aggregierten Daten:
CREATE TABLE event_uebersicht AS
SELECT
e.event_id,
e.eventname,
COUNT(s.verkauf_id) AS ticket_anzahl,
SUM(s.preis) AS gesamtumsatz,
AVG(s.preis) AS durchschnitt_ticketpreis
FROM
events e
JOIN
verkaeufe s ON e.event_id = s.event_id
GROUP BY
e.event_id, e.eventname;
Jetzt laufen Reports viel schneller auf aggregierter Ebene:
SELECT
eventname,
durchschnitt_ticketpreis
FROM
event_uebersicht;
Folgen der Denormalisierung
Denormalisierung kann Abfragen natürlich beschleunigen, aber sie ist kein Zauberstab, der alle Probleme löst. Das hier kann passieren, wenn du dich dafür entscheidest.
Erstens – Daten werden doppelt gespeichert. Wenn die gleichen Infos an mehreren Stellen liegen, wächst die Datenbank schnell und es wird schwieriger, damit zu arbeiten.
Zweitens – Daten zu aktualisieren wird jetzt komplizierter. Stell dir vor, du hast Kundendaten in der Tabelle kunden und nochmal eine Kopie davon in bestell_uebersicht. Wenn der Kunde seinen Namen oder seine Adresse ändert, musst du an beiden Stellen updaten. Wenn du das vergisst, hast du einen Fehler, weil die Daten nicht mehr übereinstimmen.
Drittens – durch diese Redundanz kann man leicht durcheinander kommen und Fehler machen. Das ist wie bei verschiedenen Versionen eines Dokuments – manchmal weiß man nicht mehr, welche Version die richtige ist.
Und schließlich: So eine Datenbank zu pflegen und weiterzuentwickeln ist schwieriger. Du musst spezielle Trigger oder Skripte schreiben, damit alle Datenkopien synchron bleiben. Das ist Extra-Arbeit für Entwickler.
Kurz gesagt: Denormalisierung ist ein Tool, das man mit Bedacht einsetzen sollte – man muss die Vor- und Nachteile kennen.
GO TO FULL VERSION