Custom Field oder eigene Entität
Custom Fields liegen als JSON ohne Index, je Sprache getrennt, in einem installationsweiten Namensraum. Drei gemessene Eigenschaften, aus denen die Entscheidung folgt.
Die Frage kommt in jedem Projekt, in dem Daten dazukommen, die Shopware nicht vorsieht: Reicht ein Custom Field, oder braucht es eine eigene Entität?
Die übliche Antwort ist eine Pro-und-Contra-Liste. Die hilft wenig, weil beide Spalten plausibel klingen. Dieser Text geht anders vor: Drei Eigenschaften von Custom Fields sind gemessen, und aus ihnen folgt die Entscheidung fast von selbst.
Der Aufbau der Messung
In einer laufenden 6.7.13.1: ein Custom-Field-Set mit einem Ganzzahlfeld angelegt, einen Wert an ein Produkt geschrieben, über die DAL gefiltert und sortiert, den Ausführungsplan der Datenbank gelesen — und danach alles wieder entfernt. Der Ausgangszustand wurde nachgeprüft.
Die drei Befunde
Erstens: JSON, und zwar je Sprache
Der Wert landet nicht am Produkt, sondern in product_translation.custom_fields
— einer JSON-Spalte in der Übersetzungstabelle. In der Datenbank sah das so
aus:
lang=2fbb5fe2… {"pixup_lieferwoche": 37}
Für einen Text ist das richtig: Ein Hinweis zur Lieferung gehört übersetzt. Für eine Lieferwoche, eine Kennung oder einen Zahlenwert ist es eine Fehlerquelle — der Wert muss in jeder Sprache gepflegt werden, und wer ihn nur in einer pflegt, hat in den anderen nichts.
Zweitens: kein Index
Auf der Spalte liegen null Indizes. Der Ausführungsplan einer Filterabfrage sagt es deutlich:
| Zugriffsart | ALL — voller Tabellendurchlauf |
| verwendeter Index | NULL |
Bei 16 Zeilen in einer Demoinstallation ist das folgenlos. Bei 200.000 Produkten in fünf Sprachen ist es eine Million Zeilen, die die Datenbank für jede Filterabfrage durchgeht.
Wichtig dabei: Filtern und Sortieren funktionieren. Wir haben beides ausgeführt — der Filter fand den einen erwarteten Treffer, die Sortierung kam zurück. Die Frage ist also nie „geht das", sondern „was kostet es".
Drittens: ein Namensraum für die ganze Installation
Der Feldname ist über einen eindeutigen Schlüssel installationsweit
gesichert, nicht je Entität. Ein Feld position am Produkt und ein Feld
position an der Kategorie schließen sich gegenseitig aus.
In der Praxis trifft das genau dann, wenn eine zweite Erweiterung dazukommt, die denselben naheliegenden Namen wählt. Deshalb die Konvention aus Hersteller und Zweck — sie ist keine Höflichkeit, sondern notwendig.
Neu in 6.7: include_in_search
Die Tabelle custom_field hat in 6.7 ein Feld dazubekommen, das es in 6.6
nicht gab: include_in_search. Damit lässt sich ein Custom Field in die
Produktsuche aufnehmen.
Das verschiebt die Entscheidung ein Stück: Ein Wert, der nur gefunden werden soll, war früher ein Argument für eine eigene Entität und ist jetzt eines für ein Custom Field. Für Filter und Sortierung ändert es nichts — der fehlende Index bleibt. Welche Felder die Suche ab Werk überhaupt anfasst, steht in Warum die Shopware-Suche nicht findet, was im Text steht.
Die Entscheidung
| Frage | ja | nein |
|---|---|---|
| Wird der Wert angezeigt und sonst nichts? | Custom Field | weiter |
| Soll er gefunden werden (Suche)? | Custom Field mit include_in_search | weiter |
| Filtert oder sortiert er Listen? | eigene Entität | weiter |
| Hat er eine Beziehung zu anderen Datensätzen? | eigene Entität | weiter |
| Braucht er eine Historie oder eigene Rechte? | eigene Entität | weiter |
| Ist er sprachunabhängig und trotzdem wichtig? | eigene Entität, oder bewusst in allen Sprachen pflegen | weiter |
| Sonst | Custom Field |
Die Zeile mit dem Filter ist die entscheidende. Alles davor ist Komfort, alles danach Architektur. Wer sie überspringt, merkt es nicht beim Anlegen, sondern zwei Jahre später an einer Listenansicht, die Sekunden braucht.
Was eine eigene Entität kostet
Damit die Empfehlung nicht einseitig wirkt — eine eigene Entität ist kein kostenloser Gewinn:
- Sie braucht eine Definition, eine Migration und eine Pflegeoberfläche.
- Sie muss bei jedem Versionswechsel mitgeprüft werden. Wie schnell eine Erweiterung still ausfällt, haben wir an einem eigenen Fall gemessen: wenn der Shopware-Kern eine Plugin-Route verdrängt.
- Sie ist ohne Entwicklung nicht anzulegen. Ein Custom Field legt jemand in fünf Minuten in der Administration an.
Genau deshalb ist die Antwort in den meisten Fällen „Custom Field" — und in den wenigen Fällen, in denen es nicht so ist, zählt es doppelt.
Der häufigste Fehler
Nicht die falsche Wahl, sondern die nachträgliche. Ein Feld wird als Custom Field angelegt, wächst über Monate in seiner Bedeutung, und irgendwann filtert eine Kategorieseite darauf. Der Umzug in eine eigene Entität ist dann kein technisches Problem, sondern ein Datenmigrationsprojekt mit allen Stellen, die inzwischen darauf zugreifen.
Die Frage lohnt sich deshalb einmal am Anfang, nicht einmal im Jahr.
Grenzen dieser Messung
Gemessen wurde an einer Demoinstallation mit 16 Übersetzungszeilen. Die Aussagen zu Speicherort, Indexlage, Ausführungsplan und Namensraum sind davon unabhängig — sie folgen aus der Struktur, nicht aus der Datenmenge. Was hier nicht gemessen wurde, ist die tatsächliche Laufzeit bei großen Katalogen. Wer eine Zahl dafür braucht, braucht eine Messung an echten Daten.
Wenn eine eigene Entität die richtige Antwort ist, gehört der Bau dazu zu App- und Plugin-Entwicklung.
Häufige Fragen
- Kann man auf Custom Fields filtern?
- Ja. Wir haben es gemessen — ein Filter über die DAL liefert das erwartete Ergebnis. Die Datenbank führt dafür aber einen vollen Tabellendurchlauf aus, weil auf der JSON-Spalte kein Index liegt.
- Warum hat ein Produkt je Sprache einen eigenen Wert?
- Weil die Spalte in der Übersetzungstabelle liegt, nicht am Produkt selbst. Das ist bei Texten gewollt und bei Zahlen oder Kennungen eine Fehlerquelle: Der Wert muss dann in jeder Sprache gepflegt werden.
- Wie viele Custom Fields sind zu viele?
- Eine Zahl gibt es nicht. Der Kipppunkt ist inhaltlich: Sobald ein Feld eine Liste filtert oder sortiert, ist die Menge nicht mehr das Problem, sondern der fehlende Index.
- Was passiert bei Namenskonflikten?
- Der Name ist installationsweit eindeutig. Legt eine zweite Erweiterung ein Feld mit demselben Namen an, scheitert das Anlegen. Deshalb der übliche Präfix aus Hersteller und Zweck.
