ohne Wahnsinn
Das EAV-Modell in Magento trennt Entitäten, Attribute und Werte auf mehrere Tabellen auf. Das macht es flexibel und gleichzeitig schwer lesbar. Dieser Artikel erklärt die Struktur vollständig und zeigt praxisnahe SQL-Muster.
Inhaltsverzeichnis
- 1. EAV-Struktur in Magento: Drei Ebenen
- 2. Die fünf Value-Tabellen
- 3. Store-Scope: store_id=0 vs. store_id=N
- 4. attribute_id per SQL finden
- 5. Produktattribut per JOIN lesen
- 6. Pivot-Query: Name, Preis, Status in einer Zeile
- 7. Warum der Flat Catalog existierte
- 8. MSI und Flat Catalog Deprecation in Magento 2.4
- 9. Unterstützung
- 10. Zusammenfassung
- 11. FAQ
1. EAV-Struktur in Magento: Drei Ebenen
EAV steht für Entity-Attribute-Value – ein Datenbankmodell, das dynamische Attribute ohne Schema-Änderungen ermöglicht. In Magento wird es für Produkte, Kategorien, Kunden und Adressen eingesetzt. Die Struktur gliedert sich in drei Ebenen: entity_type definiert die Art der Entität (z.B. Produkt), eav_attribute definiert das konkrete Attribut (z.B. "name"), und die Value-Tabellen speichern die tatsächlichen Werte.
-- Überblick: EAV Entity-Typen in Magento
SELECT entity_type_id, entity_type_code, value_table_prefix
FROM eav_entity_type;
-- Wichtige Ergebnisse:
-- entity_type_id=1: customer
-- entity_type_id=2: customer_address
-- entity_type_id=3: catalog_category
-- entity_type_id=4: catalog_product ← unser Fokus
-- entity_type_id=5: order (historisch, heute kein EAV mehr)
-- Alle Attribute eines bestimmten Entity-Typs auflisten
SELECT
attribute_id,
attribute_code,
backend_type, -- varchar, int, decimal, datetime, text, static
frontend_label,
is_required,
is_global
FROM eav_attribute
WHERE entity_type_id = 4 -- catalog_product
ORDER BY attribute_code;
Der Spalte backend_type in eav_attribute ist entscheidend: Sie gibt an, in welcher Value-Tabelle der Wert gespeichert wird. static bedeutet, der Wert steht direkt in der Entity-Tabelle (catalog_product_entity), nicht in einer separaten Value-Tabelle. Beispiele für statische Felder: sku, type_id, created_at.
2. Die fünf Value-Tabellen
Für EAV Magento SQL-Abfragen auf Produktattribute gibt es fünf spezialisierte Value-Tabellen – eine pro Datentyp. Jede Tabelle hat dieselbe Grundstruktur: value_id, attribute_id, store_id, entity_id und value.
-- Die fünf Value-Tabellen für catalog_product:
-- catalog_product_entity_varchar (backend_type='varchar') → name, url_key
-- catalog_product_entity_int (backend_type='int') → status, visibility
-- catalog_product_entity_decimal (backend_type='decimal') → price, special_price
-- catalog_product_entity_datetime (backend_type='datetime') → special_from_date
-- catalog_product_entity_text (backend_type='text') → description
-- Struktur einer Value-Tabelle (am Beispiel varchar)
DESCRIBE catalog_product_entity_varchar;
-- value_id int(11) AUTO_INCREMENT PK
-- attribute_id smallint(5) unsigned NOT NULL
-- store_id smallint(5) unsigned NOT NULL
-- entity_id int(10) unsigned NOT NULL
-- value varchar(255)
-- Alle varchar-Werte eines bestimmten Produkts ansehen
SELECT
v.attribute_id,
a.attribute_code,
v.store_id,
v.value
FROM catalog_product_entity_varchar v
JOIN eav_attribute a ON a.attribute_id = v.attribute_id
WHERE v.entity_id = 42 -- entity_id des gesuchten Produkts
ORDER BY v.attribute_id, v.store_id;
3. Store-Scope: store_id=0 vs. store_id=N
Das Store-Scope-System ist die zweite grosse Komplexitätsquelle im EAV-Modell. Jeder Attributwert kann entweder global gelten (store_id=0) oder für einen bestimmten Store (store_id=N). Der store-spezifische Wert hat Priorität über den globalen – das ist die "Store-Scope-Kaskade".
-- Store-Scope-Kaskade: store-spezifischer Wert überschreibt globalen
-- Korrekte Abfrage: erst store-spezifisch prüfen, dann Global als Fallback
SELECT
p.entity_id,
p.sku,
COALESCE(v_store.value, v_global.value) AS name_fuer_store_1
FROM catalog_product_entity p
LEFT JOIN catalog_product_entity_varchar v_global
ON v_global.entity_id = p.entity_id
AND v_global.attribute_id = (
SELECT attribute_id FROM eav_attribute
WHERE attribute_code = 'name' AND entity_type_id = 4
)
AND v_global.store_id = 0
LEFT JOIN catalog_product_entity_varchar v_store
ON v_store.entity_id = p.entity_id
AND v_store.attribute_id = v_global.attribute_id
AND v_store.store_id = 1
ORDER BY p.entity_id
LIMIT 20;
Für Backend-Reports, die keine Store-spezifischen Werte benötigen, reicht der Filter auf store_id = 0. Für Frontend-Exports oder Store-spezifische Reports muss die Kaskade wie oben beschrieben berücksichtigt werden.
4. attribute_id per SQL finden
Der erste Schritt bei jeder EAV Magento SQL-Abfrage ist das Nachschlagen der attribute_id für einen bestimmten Attribut-Code. Die attribute_id ist die Verbindungsbrücke zwischen eav_attribute und den Value-Tabellen.
-- attribute_id für bekannte Attribut-Codes finden
SELECT attribute_id, attribute_code, backend_type, frontend_label
FROM eav_attribute
WHERE entity_type_id = 4 -- catalog_product
AND attribute_code IN ('name', 'price', 'status', 'visibility',
'description', 'short_description', 'url_key',
'special_price', 'weight');
-- Typische attribute_ids (können je nach Installation variieren!):
-- 73: name (varchar)
-- 77: price (decimal)
-- 97: status (int) 1=Enabled, 2=Disabled
-- 99: visibility (int) 1=Not Visible, 4=Catalog+Search
-- 75: description (text)
-- 79: short_description (text)
-- 90: url_key (varchar)
-- WICHTIG: attribute_ids NIEMALS hardcoden!
-- Sie können je nach Magento-Version und Installation variieren.
-- Immer über eav_attribute nachschlagen:
SELECT attribute_id
FROM eav_attribute
WHERE attribute_code = 'name'
AND entity_type_id = 4;
5. Produktattribut per JOIN lesen
Das Lesen eines einzelnen Attributwerts für alle Produkte erfordert einen JOIN auf die entsprechende Value-Tabelle. Das Muster ist immer gleich: Entity-Tabelle JOIN Value-Tabelle ON entity_id + attribute_id + store_id.
-- Produktname für alle einfachen Produkte (Store-Global, store_id=0)
SELECT
p.entity_id,
p.sku,
p.type_id,
v.value AS name
FROM catalog_product_entity p
JOIN catalog_product_entity_varchar v
ON v.entity_id = p.entity_id
AND v.store_id = 0
AND v.attribute_id = (
SELECT attribute_id FROM eav_attribute
WHERE attribute_code = 'name' AND entity_type_id = 4
)
WHERE p.type_id = 'simple'
ORDER BY p.entity_id
LIMIT 50;
-- Produktpreis (decimal-Tabelle)
SELECT
p.entity_id,
p.sku,
d.value AS preis
FROM catalog_product_entity p
JOIN catalog_product_entity_decimal d
ON d.entity_id = p.entity_id
AND d.store_id = 0
AND d.attribute_id = (
SELECT attribute_id FROM eav_attribute
WHERE attribute_code = 'price' AND entity_type_id = 4
)
ORDER BY d.value DESC
LIMIT 20;
6. Pivot-Query: Name, Preis, Status in einer Zeile
Wenn mehrere Attribute in einer Zeile benötigt werden, gibt es zwei Ansätze: mehrere JOINs (einer pro Attribut) oder konditionale Aggregation. Die konditionale Aggregation mit MAX(CASE WHEN...) ist bei vielen Attributen oft performanter, da mehrere Value-Tabellen in einem Scan durchsucht werden.
-- Methode 1: Mehrere JOINs (ein JOIN pro Attribut)
-- Klar lesbar, aber bei vielen Attributen teuer
SELECT
p.entity_id,
p.sku,
vn.value AS name,
dp.value AS preis,
vi.value AS status
FROM catalog_product_entity p
LEFT JOIN catalog_product_entity_varchar vn
ON vn.entity_id = p.entity_id AND vn.store_id = 0 AND vn.attribute_id = 73
LEFT JOIN catalog_product_entity_decimal dp
ON dp.entity_id = p.entity_id AND dp.store_id = 0 AND dp.attribute_id = 77
LEFT JOIN catalog_product_entity_int vi
ON vi.entity_id = p.entity_id AND vi.store_id = 0 AND vi.attribute_id = 97
WHERE p.type_id IN ('simple', 'configurable')
LIMIT 50;
-- Methode 2: Konditionale Aggregation (Pivot via MAX(CASE WHEN))
-- Ein Scan pro Value-Tabelle, dann Pivot
SELECT
p.entity_id,
p.sku,
MAX(CASE WHEN v.attribute_id = 73 AND v.store_id = 0 THEN v.value END) AS name,
MAX(CASE WHEN v.attribute_id = 90 AND v.store_id = 0 THEN v.value END) AS url_key,
MAX(CASE WHEN d.attribute_id = 77 AND d.store_id = 0 THEN d.value END) AS preis,
MAX(CASE WHEN i.attribute_id = 97 AND i.store_id = 0 THEN i.value END) AS status,
MAX(CASE WHEN i.attribute_id = 99 AND i.store_id = 0 THEN i.value END) AS visibility
FROM catalog_product_entity p
LEFT JOIN catalog_product_entity_varchar v ON v.entity_id = p.entity_id
LEFT JOIN catalog_product_entity_decimal d ON d.entity_id = p.entity_id
LEFT JOIN catalog_product_entity_int i ON i.entity_id = p.entity_id
WHERE p.type_id = 'simple'
GROUP BY p.entity_id, p.sku
LIMIT 50;
7. Warum der Flat Catalog existierte
Das EAV-Modell ist flexibel, aber langsam für Massenabfragen. Für eine Kategorienseite mit 50 Produkten und 20 anzuzeigenden Attributen müsste eine naive EAV-Abfrage 50 × 20 = 1000 Zeilen aus verschiedenen Value-Tabellen zusammenführen. Der Flat Catalog löste dieses Problem durch Denormalisierung: eine flache Tabelle (catalog_product_flat_1 für Store 1) mit allen Attributwerten als reguläre Spalten.
-- Flat Catalog-Tabelle prüfen (wenn aktiv)
SHOW TABLES LIKE 'catalog_product_flat_%';
-- Ergibt: catalog_product_flat_1, catalog_product_flat_2 ...
-- (eine Tabelle pro Store-View)
-- Flat Catalog: Produktdaten als reguläre Spalten lesen
-- Kein EAV-JOIN notwendig
SELECT entity_id, sku, name, price, status, visibility, url_key
FROM catalog_product_flat_1
WHERE status = 1 -- 1 = Enabled
AND visibility > 1 -- 4 = Visible in Catalog and Search
ORDER BY name
LIMIT 20;
-- Flat Catalog Status prüfen
SELECT value
FROM core_config_data
WHERE path = 'catalog/frontend/flat_catalog_product';
-- value = 0: Flat Catalog deaktiviert (empfohlen ab Magento 2.4)
-- value = 1: Flat Catalog aktiv (Legacy)
8. MSI und Flat Catalog Deprecation in Magento 2.4
Mit Magento 2.4 wurden zwei wichtige Änderungen eingeführt. Multi Source Inventory (MSI) ersetzte das alte Bestandssystem und führte direkte (nicht-EAV) Tabellen ein. Gleichzeitig wurde der Flat Catalog als "deprecated" markiert – in modernen Setups mit Elasticsearch/OpenSearch wird er nicht mehr weiterentwickelt.
-- MSI: Bestand über inventory_source_item abfragen
-- (kein EAV, direkte Tabellenstruktur mit regulären Spalten)
SELECT
isi.sku,
isi.source_code,
isi.quantity,
isi.status -- 1 = in stock, 0 = out of stock
FROM inventory_source_item isi
WHERE isi.sku IN ('SKU-001', 'SKU-002', 'SKU-003')
ORDER BY isi.sku, isi.source_code;
-- Gesamtbestand über alle Quellen für alle Produkte
SELECT
isi.sku,
SUM(isi.quantity) AS gesamt_bestand,
SUM(CASE WHEN isi.status = 1 THEN isi.quantity ELSE 0 END) AS verfuegbarer_bestand
FROM inventory_source_item isi
GROUP BY isi.sku
HAVING gesamt_bestand > 0
ORDER BY gesamt_bestand DESC;
Mironsoft
Magento EAV-Abfragen, Katalog-Analysen und Datenmigration professionell umsetzen
Wir helfen, komplexe Magento-EAV-Abfragen zu schreiben, Produktdaten korrekt zu lesen und Catalog-Reports zu bauen, die auch bei grossen Produktdatenbanken performen.
EAV-Abfragen
Produktattribute korrekt lesen, Store-Scope berücksichtigen
Datenmigration
EAV-Daten exportieren, transformieren und importieren
Catalog Reports
Produktberichte mit Attributdaten korrekt und performant aufbauen
10. Zusammenfassung
Das EAV Magento SQL-Modell folgt dem Muster entity_type → eav_attribute → Value-Tabellen. Die fünf Value-Tabellen (_varchar, _int, _decimal, _datetime, _text) teilen Attributwerte nach Datentyp auf. Store-Scope-Werte (store_id=N) haben Priorität über globale Werte (store_id=0). Für Multi-Attribut-Abfragen sind konditionale Aggregation oder mehrere JOINs die gängigen Muster.
EAV Magento SQL — Das Wichtigste auf einen Blick
Drei Ebenen
entity_type (was) → eav_attribute (welches Attribut) → Value-Tabelle (Wert). backend_type in eav_attribute bestimmt die Zieltabelle.
Store-Scope
store_id=0 = Global. store_id=N = Store-spezifisch und hat Priorität. Fallback per COALESCE(store_wert, global_wert).
attribute_id
Nie hardcoden. Immer per SELECT FROM eav_attribute WHERE attribute_code = '...' AND entity_type_id = 4 nachschlagen.
Flat Catalog
Denormalisierte Tabelle pro Store-View für schnelles Lesen. Ab Magento 2.4 deprecated. MSI-Bestand ist eigenes nicht-EAV-Schema.
11. FAQ: EAV Magento SQL
1 Was ist EAV in Magento?
2 Welche Value-Tabellen gibt es für Produkte?
backend_type in eav_attribute bestimmt die Zieltabelle.3 Was bedeutet store_id=0 in Magento EAV?
COALESCE(store_wert, global_wert).4 Wie finde ich die attribute_id für einen Attribut-Code?
SELECT attribute_id FROM eav_attribute WHERE attribute_code = 'name' AND entity_type_id = 4. Nie hardcoden – IDs sind installationsabhängig.5 Wie lese ich den Produktnamen per SQL?
catalog_product_entity_varchar mit entity_id + attribute_id + store_id = 0. attribute_id per Subquery aus eav_attribute nachschlagen.6 Was ist eine Pivot-Query im EAV-Kontext?
MAX(CASE WHEN attribute_id = X THEN value END) pro Attribut pro Produkt.7 Was ist der Flat Catalog?
catalog_product_flat_N) pro Store-View mit Attributwerten als reguläre Spalten. Ab Magento 2.4 deprecated.8 Was ist entity_type_id 4?
SELECT * FROM eav_entity_type nachschlagen.9 Wie unterscheidet sich MSI von EAV?
inventory_source_item mit quantity als reguläre Spalte. Deutlich einfacher abzufragen als EAV-Strukturen.10 Soll ich attribute_ids hardcoden?
SELECT attribute_id FROM eav_attribute WHERE attribute_code = 'x' AND entity_type_id = 4 nachschlagen.