Kompromisse und andere Widerlichkeiten
Im Rahmen eines größeren CRM-Projekts (etwa 5 Mio Kunden-Datensätze) arbeite ich aktuell mit einer Tabelle „Kunden.” Um Projekt-spezifisch und ohne Sourcecode-Änderungen zusätzliche Informationen (etwa projektspezifische Informationen) speichern zu können, gibt es, verknüpft über „Kunden_ID” (1:n) eine Tabelle „Kunden_Zusatzinfos.” Die Tabelle ist eine einfache, Kunden_ID-Name-Wert-Tabelle, so dass generisch Informationen gespeichert werden können. Das ist natürlich allein schon ein Kompromiss, allerdings nicht sinnvoll anders zu lösen. Soweit, so schlecht.
Ein Problem tritt nun auf, wenn man eine Menge von Kontakten abruft, zu der ein bestimmtes Feld hinzu „gejoint” werden soll, also etwa so:
SELECT a.*,b.value AS specific_field FROM Kunden AS a LEFT JOIN Kunden_Zusatzinfos AS b ON a.Kunden_ID = b.Kunden_ID AND b.field = 'specific_field' WHERE suchkriterium
Je nach Anzahl der Kontakte kann diese Query extrem lange dauern, da aus einer zweiten Tabelle gejoint werden muss, die etwa 10x so viele Datensätze enthält. Zwar gibt es genau für sowas einen Index, aber auch der kann nur begrenzt helfen.
Abhilfe musste ich mir hier schaffen, indem ich in der Kunden-Tabelle eine weitere Spalte hinzugefügt habe, in der die Zusatz-Daten zu dem Kontakt als Array in JSON-Syntax gespeichert werden. Also z. B. ein Kontakt hat die Felder „ciao,” „newsletter,” und „lead,” so sähe das JSON-Feld so aus: {"ciao": 0, "newsletter": 1, "lead": 0}.
So kann ich ohne zusätzlichen Join alle Zusatzfelder mit auslesen. Allerdings zieht diese Methode den Nachteil der doppelten Datenhaltung mit sich: ich habe die Zusatz-Tabelle, in der die Daten stehen und die ich weiterhin brauche, um Kontakte nach spezifischen Zusatzfeldern suchen zu können und ich habe, sozusagen als Cache, das Zusatz-Feld mit der JSON-Syntax. Aber andererseits ist das halt einfach um etwa den Faktor 15 schneller als der zusätzliche Join.
Aber vielleicht fällt jemandem ja noch etwas anderes ein?
Four fucking comments!
Jeena wrote
Na dazu gibt es ja Trigger und Views damit du dir über die doppelte Datenhaltung keinen kopf mehr machen musst?
Christian Kruse wrote
Na, darum geht es ja nicht. Ich möchte einfach eine Lösung, kein herumdoktorn an den Symptomen.
Jeena Paradies wrote
Flickr macht das ja auch durch denormalisieren. Ich glaube so eine pauschale Antwort gibt es kaum, obwohl, du könntest ja vom Relationalen-Datenbankschema weggehen und was Objektorientiertes nutzen, wo die Daten schöner reinpassen, das bedeutet wiederum sehr viel Arbeit, aber du bekommst es ja bezahlt ;)
Christian Kruse wrote
Nein, kann ich nicht. Die Daten sind von Natur aus relational. Kunden <=> Kunden_Zusatzinfos ist ja nicht die einzige Relation.