Welche Kosten hinter Produktabfragen stecken
Eine Magento GraphQL-Produktabfrage, die einfach aussieht, kann intern dutzende SQL-JOINs über EAV-Tabellen auslösen. Wer nicht versteht, wie das Entity-Attribute-Value-Modell funktioniert, optimiert an der falschen Stelle. Dieser Artikel zeigt, warum EAV teuer ist, welche Maßnahmen helfen und wo die Grenzen liegen.
Inhaltsverzeichnis
- 1. EAV-Modell in Magento: Grundlagen verstehen
- 2. Welche EAV-Tabellen bei Produktabfragen betroffen sind
- 3. Wie GraphQL-Queries EAV-Abfragen auslösen
- 4. Flat-Catalog: die wichtigste EAV-Gegenmaßnahme
- 5. Custom-Attribute und ihr Einfluss auf die Performance
- 6. EAV-Kosten sichtbar machen: Profiling und Logging
- 7. EAV-Zugriffsstrategien im Vergleich
- 8. Caching-Strategien für EAV-lastige Resolver
- 9. Index-Strategie: welche Indizes wirklich helfen
- 10. Zusammenfassung
- 11. FAQ
1. EAV-Modell in Magento: Grundlagen verstehen
Das Entity-Attribute-Value-Modell (EAV) ist eine Datenbankarchitektur, die Magento für Produkte, Kunden und Kategorien verwendet. Statt alle Attribute in einer breiten Tabelle zu speichern – etwa catalog_product mit hundert Spalten –, speichert EAV jeden Attributwert als eigene Zeile in typisierten Wertetabellen. Der Vorteil: beliebig viele Custom-Attribute können ohne Schema-Änderungen hinzugefügt werden. Der Nachteil: für jedes abgefragte Attribut ist ein JOIN über die entsprechende Wertetabelle nötig.
In der Praxis bedeutet das: Eine Produktliste mit 20 Artikeln, die jeweils 30 Attribute in der GraphQL-Response enthält, kann intern über 600 EAV-Werte aus verschiedenen Tabellen zusammentragen – für jede Attribute-Wertetabelle (varchar, int, decimal, text, datetime) ein separater JOIN. Magento hat für dieses Problem Mechanismen, aber sie funktionieren nur unter bestimmten Voraussetzungen, und viele Projekte nutzen sie nicht vollständig.
2. Welche EAV-Tabellen bei Produktabfragen betroffen sind
Die EAV-Daten für Produkte sind auf fünf typisierte Wertetabellen aufgeteilt: catalog_product_entity_varchar für Texte wie Name und URL-Key, catalog_product_entity_int für ganzzahlige Werte wie Status und Sichtbarkeit, catalog_product_entity_decimal für Dezimalwerte wie Preise und Gewicht, catalog_product_entity_text für lange Texte wie Beschreibungen und catalog_product_entity_datetime für Datumsfelder. Dazu kommt catalog_product_entity als Basistabelle mit den unveränderlichen Identifiers.
Jede dieser Tabellen hat eine Zeile pro Produkt und Attribut, nicht eine Zeile pro Produkt. Wenn ein Produkt 40 Attribute hat und diese auf drei Wertetabellen verteilt sind, entstehen drei JOINs – jeweils über eine Tabelle mit mehreren Millionen Zeilen in großen Katalogen. Ohne geeignete Indizes und ohne materialisierten Flat-Catalog sind diese JOINs die häufigste Ursache für langsame Produktlisten in Magento-GraphQL-Setups.
3. Wie GraphQL-Queries EAV-Abfragen auslösen
Eine GraphQL-Query für Produkte löst in Magento eine Kette von Datenbankoperationen aus. Der Root-Resolver für products führt zunächst eine Suche oder Filterabfrage aus, die die passenden Produkt-IDs liefert. Für jede Produkt-ID werden dann die angeforderten Attribute aus den EAV-Tabellen geladen. Welche Attribute geladen werden, hängt davon ab, welche Felder in der GraphQL-Query angefragt wurden – aber nicht immer ist diese Verbindung direkt: Magento lädt intern manchmal mehr Attribute als vom Frontend explizit angefragt, weil bestimmte Attribute für die interne Verarbeitung (Preisberechnung, Berechtigungsprüfung) immer benötigt werden.
Das bedeutet: auch eine scheinbar schlanke Query mit nur sku und name kann intern mehr EAV-Zugriffe auslösen als erwartet, wenn der Resolver zusätzliche Attribute für Berechtigungsprüfungen oder Store-spezifische Preisinformationen benötigt. Ohne Query-Profiling ist dieser Overhead unsichtbar. Erst ein Blick in das SQL-Query-Log zeigt das vollständige Bild der Datenbankoperationen hinter einer scheinbar einfachen GraphQL-Query.
# This simple-looking query can trigger many EAV table joins internally
# Magento loads not just name/sku but also status, visibility, price data for authorization
query ProductListEAVTest {
products(
filter: { category_id: { eq: "10" } }
pageSize: 20
) {
total_count
items {
sku # catalog_product_entity (no JOIN needed)
name # catalog_product_entity_varchar JOIN
url_key # catalog_product_entity_varchar JOIN
status # catalog_product_entity_int JOIN
price_range {
minimum_price {
final_price { value } # complex price calculation — multiple tables
}
}
special_price # catalog_product_entity_decimal JOIN
news_from_date # catalog_product_entity_datetime JOIN
description { html } # catalog_product_entity_text JOIN
}
}
}
4. Flat-Catalog: die wichtigste EAV-Gegenmaßnahme
Der Magento Flat-Catalog ist eine Indexierungsstrategie, die EAV-Daten in materialisierten breiten Tabellen zusammenführt. Statt beim Laden eines Produkts über fünf JOINs Attribute aus EAV-Wertetabellen zu sammeln, enthält catalog_product_flat_1 (für Store 1) alle Attribute als eigene Spalten – ein einfacher SELECT reicht aus. Die Tabelle wird beim Indexieren (bin/magento indexer:reindex catalog_product_flat) aktualisiert und bleibt bis zur nächsten Reindizierung gültig.
Der Flat-Catalog ist standardmäßig nicht aktiviert und muss im Admin unter Stores > Configuration > Catalog > Catalog > Storefront eingeschaltet werden. Nach der Aktivierung muss einmal vollständig reindiziert werden. Der Gewinn ist erheblich: Produktlistenabfragen, die ohne Flat-Catalog dutzende JOINs erzeugen, reduzieren sich auf einen einzigen Table-Scan der Flat-Tabelle. Für Stores mit vielen Custom-Attributen und großen Katalogen ist das oft der größte einzelne Performance-Hebel überhaupt.
5. Custom-Attribute und ihr Einfluss auf die Performance
Jedes Custom-Attribut, das über ein eigenes Modul zum Produkt-Entitätstyp hinzugefügt wird, erhöht die EAV-Komplexität. Wenn ein Attribut dem Flat-Catalog hinzugefügt wird, ist der Overhead minimal – es erscheint als zusätzliche Spalte in der Flat-Tabelle. Wenn ein Attribut nicht im Flat-Catalog ist, erfordert jeder Zugriff einen zusätzlichen JOIN über die EAV-Wertetabelle. Eigene Module müssen deshalb explizit angeben, ob ihre Attribute in den Flat-Catalog aufgenommen werden sollen.
Ein weiteres Problem entsteht bei Attributen mit hoher Kardinalität: Attribut-Sets mit vielen Optionen (z.B. Farbe mit 500 Werten) erzeugen in der catalog_product_entity_int-Tabelle viele Zeilen, deren Auflösung über eav_attribute_option_value wieder ein JOIN ist. Für GraphQL-Responses, die Attribute-Labels statt numerischer IDs zurückgeben, multiplizieren sich diese JOINs weiter. Resolver, die Attribut-Labels für Filteroptionen zurückgeben, sollten deshalb gecachte Lookup-Tabellen verwenden statt bei jedem Request über die Option-Tabellen zu joinen.
6. EAV-Kosten sichtbar machen: Profiling und Logging
Der erste Schritt zur EAV-Optimierung ist das Sichtbarmachen der tatsächlichen Datenbankkosten. Der Magento SQL-Query-Logger zeigt alle SQL-Abfragen eines Requests mit Ausführungszeiten. Für eine GraphQL-Produktlisten-Query sollte man zählen, wie viele der Queries gegen EAV-Tabellen gehen und wie viel Zeit sie zusammen verbrauchen. In einem schlecht konfigurierten Setup sieht man häufig, dass 70–90 % der Request-Zeit in EAV-Tabellen-JOINs verbracht wird.
Für tiefergehende Analyse empfiehlt sich MySQL's EXPLAIN-Befehl für die häufigsten Queries. Ein Query ohne geeigneten Index, der über eine Millionen-Zeilen-EAV-Tabelle scannt, ist sofort an einem type: ALL in der EXPLAIN-Ausgabe erkennbar. Für Magento-Projekte ist es sinnvoll, periodisch einen Query-Profiling-Lauf durchzuführen und die Top-10-teuersten SQL-Queries zu identifizieren – in produktiven Stores kommen diese fast immer aus EAV-Abfragen oder fehlenden Indizes.
7. EAV-Zugriffsstrategien im Vergleich
Es gibt mehrere Strategien, den EAV-Overhead zu reduzieren. Die Wahl der richtigen Strategie hängt von der Größe des Katalogs, der Anzahl der Custom-Attribute und den Anforderungen an Datenaktualität ab.
| Strategie | Performance-Gewinn | Komplexität | Einschränkungen |
|---|---|---|---|
| Flat-Catalog aktivieren | Sehr hoch | Gering | Braucht regelmäßige Reindizierung |
| Attribute zum Flat-Catalog hinzufügen | Hoch | Mittel | Nur bei Standard-EAV-Attributen einfach |
| Response-Cache für Produktlisten | Sehr hoch (bei Cache-Hit) | Mittel | Nur anonyme Requests; Cache-Invalidierung nötig |
| Attribut-Label-Cache im Service | Mittel | Mittel | Nur für Option-Label-Lookups relevant |
| Elasticsearch/OpenSearch für Suche | Sehr hoch (für Suchabfragen) | Hoch | Nur für Suchabfragen, nicht für direkte Abrufe |
8. Caching-Strategien für EAV-lastige Resolver
Der effektivste Cache für EAV-lastige Resolver ist der Magento Response-Cache, der eine vollständige GraphQL-Response für anonyme Queries speichert. Bei einem Cache-Hit wird die Response direkt aus dem Cache gelesen, ohne dass eine einzige Datenbankabfrage stattfindet – EAV-Overhead inklusive. Der Response-Cache erfordert eine korrekt konfigurierte Identity-Klasse, die Cache-Tags setzt, und ist standardmäßig für öffentliche Produktabfragen aktiviert.
Für Resolver, die produktbezogene Attribute zurückgeben und keinen vollständigen Response-Cache nutzen können (etwa authentifizierte Queries), empfiehlt sich ein feldspezifischer Cache auf Service-Ebene. Produktattribute, die sich selten ändern – Name, Beschreibung, URL-Key, Bilder –, können im Magento-Cache oder Redis zwischengespeichert werden. Das Laden dieser Werte aus dem Cache ist um Größenordnungen schneller als ein EAV-JOIN, selbst für einzelne Produkte. Die Cache-Invalidierung erfolgt über die Magento-Indexer, die beim Produktspeichern automatisch ausgelöst werden.
9. Index-Strategie: welche Indizes wirklich helfen
Magento pflegt für die EAV-Tabellen eigene Indizes, aber in großen Installationen mit vielen Custom-Attributen und hohem Traffic können diese nicht ausreichen. Der wichtigste Index für EAV-Performanceabfragen ist ein zusammengesetzter Index auf (entity_id, attribute_id, store_id) in den EAV-Wertetabellen – dieser deckt die häufigsten Abfragmuster ab. In MySQL/MariaDB kann man mit EXPLAIN prüfen, ob bestehende Abfragen diesen Index verwenden.
Für den catalog_product_flat-Index-Prozess selbst ist es wichtig zu verstehen, dass partielle Reindizierungen (nur für geänderte Produkte) möglich sind und in produktiven Systemen deutlich schneller sind als vollständige Reindizierungen. Die Konfiguration von mview.xml und den Index-Mode-Einstellungen bestimmt, wann und wie der Flat-Catalog aktualisiert wird. Realtime-Reindizierung (Update on Save) ist für kleinere Kataloge geeignet; für große Stores mit häufigen Preisänderungen empfiehlt sich geplante Reindizierung außerhalb der Stoßzeiten.
# Query optimized for Flat-Catalog — all requested fields should be in the flat table
# Check with: SHOW COLUMNS FROM catalog_product_flat_1
query FlatCatalogOptimizedQuery {
products(
filter: { category_id: { eq: "5" } }
pageSize: 24
currentPage: 1
) {
total_count
items {
# These fields are typically in the flat table — one SELECT, no EAV JOINs
sku
name
url_key
status
visibility
# Price comes from price index, not EAV
price_range {
minimum_price {
final_price { value currency }
regular_price { value }
}
}
# Image from media gallery index
small_image { url label }
}
}
}
10. Zusammenfassung
Das EAV-Modell ist der größte versteckte Performance-Faktor bei Magento GraphQL-Produktabfragen. Jedes abgefragte Attribut kann einen oder mehrere JOINs über EAV-Wertetabellen auslösen, und ohne Flat-Catalog multipliziert sich dieser Overhead mit der Anzahl der Produkte in der Ergebnisliste. Profiling mit dem SQL-Query-Logger macht diese Kosten sichtbar und zeigt, wo die meiste Zeit verbracht wird.
Die wirksamsten Gegenmaßnahmen sind Flat-Catalog aktivieren und Custom-Attribute explizit einbinden, Response-Cache für anonyme Produktlisten konfigurieren und feldspezifisches Caching für sich selten ändernde Attribute implementieren. Wer diese Maßnahmen kombiniert, kann die Ladezeit einer typischen Produktlisten-Query um 60–90 % reduzieren – ohne die GraphQL-Schnittstelle oder den Schema-Aufbau ändern zu müssen.
Magento GraphQL & EAV — Das Wichtigste auf einen Blick
EAV-Grundproblem
Jedes Attribut = ein JOIN über eine typisierte Wertetabelle. 20 Produkte × 30 Attribute = potenziell 600 EAV-Zugriffe pro GraphQL-Request ohne Flat-Catalog.
Flat-Catalog
Aktivieren und Custom-Attribute einbinden. Materialisiert EAV-Daten in eine breite Tabelle – ein SELECT statt dutzender JOINs. Größter einzelner Performance-Hebel.
Profiling
SQL-Query-Logger aktivieren und EAV-Queries zählen. EXPLAIN für häufige Queries ausführen und auf fehlende Indizes prüfen. Erst messen, dann optimieren.
Caching
Response-Cache für anonyme Produktlisten ist die effektivste Maßnahme. Feldspezifischer Cache für Attribute, die sich selten ändern, als Ergänzung für authenticated Queries.
11. FAQ: Magento GraphQL und EAV
1Warum ist EAV ein Performance-Problem?
2Was ist der Flat-Catalog und wie hilft er?
3Muss nach jeder Produktänderung reindiziert werden?
4Welche EAV-Tabellen sind relevant?
entity_varchar, entity_int, entity_decimal, entity_text, entity_datetime – je nach Attributtyp. Alle unter catalog_product_entity_*.5Wie Custom-Attribut zum Flat-Catalog hinzufügen?
used_in_product_listing = true im Attribut-Setup setzen. Dann catalog_product_flat reindizieren. Konfiguration im Modul über Setup- oder Upgrade-Skript.6Wie EAV-Performance-Probleme erkennen?
catalog_product_entity_* zählen. EXPLAIN zeigt ob Indizes fehlen. Mehr als 10 EAV-Queries pro GraphQL-Request ist ein klares Signal.