EAV - ist es in allen Szenarien wirklich schlecht?

65

Ich überlege, ein Entity-Attribute-Value-Modell (EAV) für einige der in einem der Projekte enthaltenen Elemente zu verwenden, aber alle Fragen dazu in Stack Overflow führen dazu, dass die Antwort lautet, dass EAV ein Anti-Pattern ist.

Aber ich frage mich, ob es in allen Fällen so falsch ist.

Nehmen wir an, die Produktentität des Shops weist gemeinsame Merkmale wie Name, Beschreibung, Bild und Preis auf, die an vielen Orten logisch beteiligt sind, und (halb-) einzigartige Merkmale wie Uhr und Wasserball, die durch ganz unterschiedliche Aspekte beschrieben werden. Ich denke also, dass EAV für die Speicherung dieser (halb-) einzigartigen Funktionen geeignet wäre.

All dies setzt voraus, dass für die Anzeige der Produktliste genug Informationen in der Produkttabelle (dh es ist kein EAV beteiligt) vorhanden sind und nur für die Anzeige eines Produkts / für den Vergleich von bis zu 5 Produkten / usw. Daten, die mit EAV gespeichert wurden, werden verwendet.

Ich habe einen solchen Ansatz im Magento-Handel gesehen und er ist sehr beliebt. Gibt es also Fälle, in denen EAV sinnvoll ist?

Giedrius
quelle
2
@busy_wait "Entity-Attibute-Value" -Tabellen - siehe Entity-Attribut-Wert-Modell auf Wikipedia .
Ross Patterson
Ein Beispiel für das gut funktionierende EAV-Muster finden Sie in der Datomic-Datenbank. Es speichert alles im EAVT-Muster (T ist ein "Zeitstempel", eigentlich eher eine Transaktions-ID). Ihre [Indizierungsdokumentation] (docs.datomic.com/indexes.html) scheint dies am besten zu zeigen. Ein Beispiel für ein schreckliches EAV finden Sie unter Wordpress .
Dan Ross

Antworten:

80

https://web.archive.org/web/20140831134758/http://www.dbforums.com/database-concepts-design/1619660-otlt-eav-design-why-do-people-hate.html

EAV bietet dem Entwickler die Flexibilität, das Schema nach Bedarf zu definieren. Dies ist unter bestimmten Umständen hilfreich.

Auf der anderen Seite ist die Leistung bei einer schlecht definierten Abfrage sehr schlecht und kann andere schlechte Praktiken unterstützen.

Mit anderen Worten, EAV gibt Ihnen genug Seil, um sich zu erhängen, und in dieser Branche sollten die Dinge auf das niedrigste Maß an Komplexität ausgelegt werden, da der Typ, der Sie im Projekt ersetzt, wahrscheinlich ein Idiot sein wird.

maple_shaft
quelle
32
Lieben Sie den letzten Satz.
Zohar Peled
2
Fauler Link. Gibt es irgendwo eine zwischengespeicherte Version?
Wildcard
1
Folgen Sie nicht dem Link. Die Seite wird langsam geladen und ist nicht hilfreich. Außerdem stinken solche Foren im alten Stil. Verwenden Sie stattdessen den Stapelüberlauf! Stimmen Sie gute / hilfreiche Antworten ab und werfen Sie den Müll runter.
Jess
29

Kurz gesagt, EAV ist nützlich, wenn Ihre Attributliste häufig wächst oder wenn sie so groß ist, dass die meisten Zeilen mit NULL-Werten gefüllt werden, wenn Sie jedes Attribut zu einer Spalte machen. Es wird zu einem Anti-Pattern, wenn es außerhalb dieses Kontexts verwendet wird.

Karl Bielefeldt
quelle
16
Ich würde "häufig" ersetzen durch "muss die Möglichkeit zur Laufzeit geändert werden".
Doc Brown
3
Wir können Doc Brown noch weiter verkürzen, indem wir das ziemlich gut verstandene Wort "dynamisch" verwenden - EAV ist nützlich, wenn sich Ihre Attributliste dynamisch ändern kann.
Alexander Mills
Noch weiter zu "wann sich Ihre Attribute ändern können" - "dynamisch" ist in diesem Zusammenhang ein bisschen überflüssig :)
Wranorn
1
Ist es notwendigerweise nützlicher, als beispielsweise das Formular zum Ändern eines Attributs CREATE TABLEfür das neue Attribut ausführen zu lassen ?
Damian Yerrick
@ DamianYerrick interessanter Ansatz. Hast du das in der Produktion benutzt?
Digout
21

Nehmen wir an, die Produktentität des Shops weist gemeinsame Merkmale wie Name, Beschreibung, Bild, Preis usw. auf, die an vielen Orten an der Logik beteiligt sind und (halb) einzigartige Merkmale aufweisen, wie Uhr und Wasserball, die durch ganz unterschiedliche Aspekte beschrieben werden würden . Ich denke also, dass EAV für die Speicherung dieser (halb-) einzigartigen Funktionen geeignet wäre?

Die Verwendung einer EAV-Struktur für hat mehrere Auswirkungen, die Kompromisse darstellen.

Sie tauschen weniger Platz für die Zeile aus, weil Sie nicht über 100 Spalten verfügen, die nullfür komplexere Abfragen und Modelle stehen.

Ein EAV zu haben bedeutet normalerweise, dass der Wert eine Zeichenfolge ist, in die man beliebige Daten einfügen kann. Dies hat dann Auswirkungen auf die Gültigkeits- und Beschränkungsprüfung. Betrachten Sie die Situation, in der Sie die Anzahl der verwendeten Batterien in die EAV-Tabelle eingetragen haben. Sie möchten eine Taschenlampe finden, die Batterien der Größe C verwendet, aber weniger als 4 davon.

select P.sku
from
  products P
  attrib Ab on (P.sku = Ab.sku and Ab.key = "batteries")
  attrib Ac on (P.sku = Ac.sku and Ac.key = "count")
where
  cast(Ac.value as int) < 4
  and Ab.value = 'C'
  ...

Hier ist zu beachten, dass Sie keinen vernünftigen Index für den Wert verwenden können. Sie können auch nicht verhindern, dass jemand etwas eingibt, das dort keine Ganzzahl ist, oder eine ungültige Ganzzahl (verwendet '-1' Batterien), da die Wertespalte immer wieder für andere Zwecke verwendet wird.

Dies hat dann Auswirkungen auf den Versuch, ein Modell für das Produkt zu schreiben. Hier finden Sie die schöne typisierten Werte haben ... aber du bist auch ein haben , Map<String,String>gerade dort mit allen möglichen Sitz Sachen drin. Dies hat dann weitere Auswirkungen auf die Serialisierung in XML oder Json und die Komplexität des Versuchs, Validierungen oder Abfragen für diese Strukturen durchzuführen .

Einige Alternativen oder Modifikationen des zu berücksichtigenden Musters bestehen darin, anstelle eines Freiformschlüssels eine andere Tabelle mit gültigen Schlüsseln zu haben. Dies bedeutet, dass Sie anstelle von Zeichenfolgenvergleichen in der Datenbank die Gleichheit von Fremdschlüssel-IDs überprüfen. Das Ändern des Schlüssels selbst erfolgt an einer Stelle. Sie haben einen bekannten Satz von Schlüsseln, was bedeutet, dass sie als Aufzählung durchgeführt werden können.

Sie können auch verknüpfte Tabellen haben, die Attribute einer bestimmten Produktklasse enthalten. Eine Lebensmittelabteilung könnte einen anderen Tisch haben, dem mehrere Attribute zugeordnet sind, die das Baumaterial nicht benötigt (und umgekehrt).

+----------+    +--------+    +---------+
|Grocery   |    |Product |    |BuildMat |
|id (fk)   +--->|id (pk) |<---+id (fk)  |
|expiration|    |desc    |    |material |
|...       |    |img     |    |...      |
+----------+    |price   |    +---------+
                |...     |               
                +--------+               

Es gibt Zeiten, in denen besonders eine EAV-Tabelle erforderlich ist.

Stellen Sie sich vor, Sie schreiben nicht nur ein Inventarsystem für Ihr Unternehmen, in dem Sie jedes Produkt und jedes Attribut kennen. Sie schreiben jetzt ein Inventarsystem, um es an andere Unternehmen zu verkaufen. Sie können nicht jedes Attribut jedes Produkts kennen - sie müssen sie definieren.

Eine Idee, die herauskommt, ist "wir lassen den Kunden die Tabelle modifizieren", und das ist nur schlecht (Sie kommen in die Metaprogrammierung für Tabellenstrukturen, weil Sie nicht mehr wissen, wo sich diese befinden, sie können die Struktur auf königliche Weise durcheinander bringen oder beschädigt werden In der Anwendung haben sie Zugriff darauf, um falsche Dinge zu tun, und die Auswirkungen dieses Zugriffs werden erheblich. In MVC4 gibt es mehr zu diesem Pfad : Wie erstelle ich ein Modell zur Laufzeit?

Stattdessen erstellen Sie die Verwaltungsschnittstelle zu einer EAV-Tabelle und lassen zu, dass diese verwendet wird. Wenn der Kunde einen Eintrag für 'Polkadots' erstellen möchte, wird dieser in die EAV-Tabelle eingetragen, und Sie wissen bereits, wie Sie damit umgehen müssen.

Ein Beispiel hierfür ist im Datenbankmodell für Redmine zu sehen. Sie können die Tabelle custom_fields und die Tabelle custom_values ​​sehen. Dies sind Teile des EAV, mit denen das System erweitert werden kann.


Beachten Sie, dass Sie sich die KV-Variante von NoSQL (Cassandra, Redis, Mongo, ...) ansehen sollten, wenn Ihre gesamte Tabellenstruktur eher wie EAV als wie relational aussieht . Beachten Sie, dass diese häufig mit anderen Kompromissen in ihrem Design einhergehen, die möglicherweise nicht dem entsprechen, wofür Sie sie verwenden. Sie sind jedoch speziell mit der Absicht einer EAV-Struktur entworfen.

Möglicherweise möchten Sie SQL vs NoSQL für ein Bestandsverwaltungssystem lesen

Wenn Sie diesem Ansatz mit einer dokumentenorientierten NoSQL-Datenbank (couch, mongo) folgen, können Sie jedes Inventarelement als Dokument auf einer Festplatte betrachten. Das Aufrufen aller Elemente in einem einzelnen Dokument geht schnell. Darüber hinaus ist das Dokument so strukturiert, dass Sie jede einzelne Sache schnell herausziehen können. Auf der anderen Seite kann das Durchsuchen aller Dokumente nach Dingen, die einem bestimmten Attribut entsprechen, eine geringere Leistung haben (vergleiche 'grep' mit allen Dateien) ... es ist alles ein Kompromiss.

Ein anderer Ansatz wäre LDAP, bei dem eine Basis mit allen zugehörigen Elementen vorhanden ist, auf die dann jedoch auch zusätzliche Objektklassen für die anderen Elementtypen angewendet werden. (siehe Systeminventarisierung mit LDAP )

Wenn Sie diesen Weg einmal eingeschlagen haben, werden Sie vielleicht etwas finden, das genau zu dem passt, wonach Sie suchen ... obwohl alles mit gewissen Kompromissen verbunden ist.

Gemeinschaft
quelle
10

6 Jahre später

Jetzt, da JSON in Postgres verfügbar ist, haben wir eine weitere Option für diejenigen, die Postgres verwenden. Wenn Sie nur einige zusätzliche Daten an ein Produkt anhängen möchten, sind Ihre Anforderungen recht einfach. Beispiel:

CREATE TABLE products (sku VARCHAR(30), shipping_weight REAL, detail JSON);
INSERT INTO products ('beachball', 1.0, '{"colors": ["red", "white"], "diameter": "50cm"}');

SELECT * FROM products;
    sku    | weight |               detail               
-----------+--------+------------------------------------
 beachball |      1 | {"colors": ["red", "white"], "diameter": "50cm"}

Hier ist eine leichtere Einführung in JSON in Postgres: https://www.compose.com/articles/is-postgresql-your-next-json-database/ .

Beachten Sie, dass Postgres tatsächlich JSONB und nicht JSON im Klartext speichert und Indizes für Felder in einem JSONB-Dokument / -Feld unterstützt, falls Sie feststellen, dass Sie tatsächlich eine Abfrage nach diesen Daten durchführen möchten.

Beachten Sie außerdem, dass Felder in einem JSONB-Feld nicht einzeln mit einer UPDATE-Abfrage geändert werden können. Sie müssten den gesamten Inhalt des JSONB-Felds ersetzen.

Diese Antwort behandelt die Frage möglicherweise nicht direkt, bietet jedoch eine Alternative zu einem EAV-Muster, das jeder berücksichtigen sollte, der über die ursprüngliche Frage nachdenkt.

Dan Ross
quelle
3
Ich halte es für eine großartige Idee, eine alternative Lösung zu posten. Um andere auf dem Laufenden zu halten, unterstützte MS SQL XML-Spalten mit der Möglichkeit, diese für eine Weile zu indizieren, und ab 2016 kann es dasselbe mit JSON tun (obwohl JSON kein nativer Spaltentyp in MS SQL ist, können Sie es dennoch indizieren) ). Auf der anderen Seite ist die Postgres-JSON-Unterstützung nach meiner Lektüre besser, es sieht beispielsweise so aus, als ob sie Indizes für Daten in JSON-Array-Eigenschaften unterstützt.
Giedrius
1
"... Felder in einem JSONB-Feld können nicht einzeln mit einer UPDATE-Abfrage geändert werden. Sie müssten den gesamten Inhalt des JSONB-Felds ersetzen." Das ist veraltet, nicht wahr? jsonb_set()In Postgres 9.5 und höher gibt es eine Funktion, die genau dafür vorgesehen ist. (Der Artikel, den Sie mit Links verknüpft haben, führt zu einem neueren Artikel, in dem die 9.5-Funktionen hinzugefügt wurden .)
Wildcard,
7

In der Regel schauen die Benutzer in die andere Richtung, wenn Sie es für Nachschlagetabellen verwenden, oder in anderen Situationen, in denen der Vorteil darin besteht, keine Tabellen für einen oder zwei gespeicherte Werte erstellen zu müssen. Die von Ihnen beschriebene Situation, in der Sie Elementeigenschaften speichern, klingt völlig normal (und normalisiert). Das Erweitern einer Tabelle zum Speichern einer variablen Anzahl von Elementattributen ist eine schlechte Idee.

Für den allgemeinen Fall, dass unterschiedliche Daten in einer langen, dünnen Tabelle gespeichert werden ... Sie sollten keine Angst haben , neue Tabellen zu erstellen, wenn dies erforderlich ist, und nur eine oder zwei lange, dünne Tabellen sind nicht viel besser als nur eine oder zwei zwei kurze fette Tische.

Abgesehen davon bin ich dafür berüchtigt, EAV-Tabellen für die Protokollierung zu verwenden. Sie haben einen guten Nutzen.

Satanicpuppy
quelle
Bitte definieren Sie "Skinny Table" und "Fat Table".
Tulains Córdova
@ TulainsCórdova: Eine "dünne" Tabelle würde eine mit wenigen Zeilen und vielen Spalten sein, während eine dicke Tabelle eine mit vielen Spalten und wenigen Zeilen ist. Ein Beispiel wäre das Erstellen einer Nachschlagetabelle, in der Sie Eigenschaften haben, zum Beispiel Bücher. Eine fette Tabelle hätte einen Datensatz pro Buch mit vielen Spalten für bestimmte Daten, während eine dünne Tabelle möglicherweise vier Spalten wie id, book, field_name, field_data hätte. Der Vorteil des ersten ist, dass es weniger Datensätze gibt, aber das Negative ist, dass einige Felder leer sein können und das Ganze schwieriger zu erweitern ist.
Satanicpuppy
@Satanicpuppy Ich denke, deine Skinny / Fat-Definitionen sind durcheinander - sie sind gleich. Meinen Sie damit, dass eine dünne Tabelle nur wenige Spalten und viele Zeilen enthält?
Charles Wood
1

EAV wandelt das Problem der expliziten Struktur in implizite Wahrnehmung um. Anstatt zu sagen, dass X eine Tabelle mit den Spalten A und B ist, implizieren Sie, dass die Spalten A und B die Tabelle X bilden. In gewisser Hinsicht ist es umgekehrt, aber es gibt nicht unbedingt eine Eins-zu-Eins-Zuordnung. Man könnte sagen, dass A und B beide Tabellen (oder Typen) X und Y zugeordnet sind. Dies könnte in den Bereichen, in denen es auf den Kontext ankommt, wichtig sein.

Ich habe Datomic für diese Art von Ansatz studiert und ich denke, es ist ein sehr nützliches und leistungsfähiges System mit Einschränkungen, was Sie damit machen sollten (nicht, dass Sie es nicht könnten).

Dass EAV langsam ist oder "genug Seil gibt, um sich aufzuhängen", ist keine Aussage, der ich zustimmen würde. Eher würde ich die Stärken von EAV stärker betonen und wenn es Ihrem Problemraum entspricht, sollten Sie es in Betracht ziehen.

Ich habe die Erfahrung gemacht, dass dies ein wunderbarer, fast uneingeschränkter Ansatz für die Modellierung ist. Insbesondere im Fall von Datomic schreiben sie über allem eine festgelegte Semantik vor. Jede Modellierungsentscheidung, die eine Beziehung modelliert, kann frei von einer bis zu mehreren getroffen werden, ohne dass Spalten / Tabellen neu entworfen werden müssen. Sie können auch zurückgehen, solange die Einschränkung nicht gegen die Invariante verstößt. Unter der Haube ist es egal.

Das Problem mit EAV war in meinen Augen das Fehlen einer Implementierung wie Datomic. Da dies eine Frage zu EAV ist, möchte ich nicht über Datomic schwärmen, aber es ist eines dieser Dinge, bei denen ich denke, dass sie in Bezug auf EAV alles richtig gemacht haben.

John Leidegren
quelle