Save Ukraine

Kompromisse und andere Widerlichkeiten

Christian Kruse,

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?