Ankündigung

Einklappen
Keine Ankündigung bisher.

Umgang mit EAV-Modell

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Umgang mit EAV-Modell

    Vorweg: Nein, kein Schreibfehler, nicht EVA, sondern EAV für Entity-Attribut-Value-Modell. Hier zu lesen bei Wikipedia (engl.).
    Im Thema 50 Datensätze gleichzeitig speichern wurde der Umgang damit auf die Verwendung des JSON-Format reduziert, hier zwei Alternativen zur Gestaltung von Abfragen:

    Datenbank:
    Code:
    CREATE TABLE IF NOT EXISTS `tbl_adresse_eav` (
    `AdresseEAV_ID` int(11) NOT NULL,
      `AdresseID_FK` int(11) NOT NULL,
      `AttributName` text NOT NULL,
      `Wert` text NOT NULL
    ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
    
    INSERT INTO `tbl_adresse_eav` (`AdresseEAV_ID`, `AdresseID_FK`, `AttributName`, `Wert`) VALUES
    (1, 1, 'Nachname', 'Müller'),
    (2, 1, 'Vorname', 'Heinz'),
    (3, 1, 'Ort', 'Hamburg'),
    (4, 2, 'Nachname', 'Meier'),
    (5, 2, 'Vorname', 'Hans'),
    (6, 2, 'Ort', 'Bremen');
    
    ALTER TABLE `tbl_adresse_eav`
     ADD PRIMARY KEY (`AdresseEAV_ID`);
    
    ALTER TABLE `tbl_adresse_eav`
    MODIFY `AdresseEAV_ID` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=7;
    Möglichkeit 1 für DBMS, die Pivot-Funktion haben:
    Code:
    TRANSFORM First(tbl_adresse_eav.Wert) AS ErsterWertvonWert
    SELECT tbl_adresse_eav.AdresseID_FK
    FROM tbl_adresse_eav
    GROUP BY tbl_adresse_eav.AdresseID_FK
    PIVOT tbl_adresse_eav.AttributName;
    Möglichkeit 2 für DBMS, die die nicht haben (z.B. MySQL):
    Code:
    SELECT tbl_adresse_eav.AdresseID_FK,
        Max(If(AttributName='Nachname', Wert, '')) AS Nachname,
        Max(If(AttributName='Vorname', Wert, '')) AS Vorname,
        Max(If(AttributName='Ort', Wert, '')) AS Ort
    FROM tbl_adresse_eav
    GROUP BY tbl_adresse_eav.AdresseID_FK;

  • #2
    Was war doch gleich die Frage?
    [SIZE="1"]Atwood's Law: any application that can be written in JavaScript, will eventually be written in JavaScript.[/SIZE]

    Kommentar


    • #3
      Ist keine Frage, soll wohl eher als Hilfestellung dienen.
      Competence-Center -> Enjoy the Informatrix
      PHProcks!Einsteiger freundliche TutorialsPreComposed Packages

      Kommentar


      • #4
        Ich würde noch ein Unique Key auf (`AdresseID_FK`, `AttributName`) setzen, damit jeder Eintrag auch nur einmal das Attribut gesetzt haben kann.

        Ich war eine Zeit lang auch ein Fan vom EAV Prinzip. Allerdings zeigt diese Variante hier nur die einfachste.
        Eigentlich bräuchte man noch je DatenTyp eine eigene Tabelle, so wie eine für die definierten FormSets usw. Wenn man sich eine komplette Umsetzung anschauen möchte, kann man dies ganz gut an Magento machen.
        https://devdocs.magento.com/guides/m...for-dev-7.html

        Dort wird dann auch sehr schnell klar, wie komplex und übersichtlich das ganze werden kann. Auch gibt es unter MySQL dann das Problem, dass man auf 61 Attribute begrenzt ist, da soweit ich das noch im Kopf habe MySQL maximal 61 Joins je Abfrage unterstützt. (https://dev.mysql.com/doc/refman/5.7...ns-limits.html) Auch das suchen in solchen EAV Modellen ist relativ aufwendig wie ich finde.

        Mittlerweile bin ich für mich zu der Einsicht gelangt, dass man wenn man diese Art von dynamischen Datenstrukturen braucht mit Dokumenten basierten Datenbank deutlich schneller und übersichtlicher zum Ziel gelangt und ich sogar soweit gehen würde, dass EAV ein Anti-Pattern sein sollte. Relationale Datenbanken sind perfekt für Strukturierte Daten, welche sich gut in Tabellenstrukturen umsetzten lassen. Sollten aber unstrukturierte/dynamische Datenstrukturen vorliegen, sollte man lieber eine Dokumenten basierte Datenbank einsetzten. Es spricht auch nichts dagegen, in einem Projekt mehr als eine DB einzusetzen und diese Sinnvoll zu kombinieren.

        Noch ein interessanter Artikel zu dem Thema:
        https://mikesmithers.wordpress.com/2...tabase-design/

        Kommentar


        • #5
          Ack. Magento knickt sehr schnell ein, wenn man mehr als 1 Dutzend Artikel oder so im Angebot hat. Würde man den Krempel mal umschreiben und PG nutzen und da entweder HSTORE oder JSONB nutzen könnte das richtig gut werden ... die Diskussion geht da ja schon seit Jahren. In einem meiner früheren Leben war ich Techniker bei einem Hosting-Provider, da haben wir tagtäglich gesehen, wie schnell Magento da zum Problem wird.
          PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

          Kommentar


          • #6
            Zitat von akretschmer Beitrag anzeigen
            Ack. Magento knickt sehr schnell ein, wenn man mehr als 1 Dutzend Artikel oder so im Angebot hat. Würde man den Krempel mal umschreiben und PG nutzen und da entweder HSTORE oder JSONB nutzen könnte das richtig gut werden ... die Diskussion geht da ja schon seit Jahren. In einem meiner früheren Leben war ich Techniker bei einem Hosting-Provider, da haben wir tagtäglich gesehen, wie schnell Magento da zum Problem wird.
            Das stimmt, der größte Flaschenhals bei Magento ist das EAV Modell. Allerdings muss ich auch sagen, dass Magento zwar relativ langsam ist, aber auch unter Last nicht noch viel langsamer wird. Insgesamt bestätigt das aber meine Kritik am EAV Modell.

            Kommentar


            • #7
              Zitat von Zeichen32 Beitrag anzeigen
              Ich würde noch ein Unique Key auf (`AdresseID_FK`, `AttributName`) setzen, damit jeder Eintrag auch nur einmal das Attribut gesetzt haben kann.
              Gute Idee.

              Ich war eine Zeit lang auch ein Fan vom EAV Prinzip. Allerdings zeigt diese Variante hier nur die einfachste.
              Eigentlich bräuchte man noch je DatenTyp eine eigene Tabelle
              Üblich ist eine Tabelle mit den Attributen, die Datentyp als FK und weitere Infos enthält und eine Tabelle mit den Datentypen, aber nicht eine Tabelle "je Datentyp".
              ... so wie eine für die definierten FormSets usw.
              Da weiß ich jetzt mal wieder nicht, was "FormSets" sein sollen, also gegoogelt jede Menge gefunden, aber nichts, was auf eine Definition hinausläuft - hätte nichts dagegen, wenn solche Begriffe bitte künftig kurz erläutert würden!
              Wenn man sich eine komplette Umsetzung anschauen möchte, kann man dies ganz gut an Magento machen.
              Gut, aber hier wollen wir doch erstmal lernen, wie's geht und nicht für die Vermarktung anderer Leute Produkte sorgen, ... ?!

              Dort wird dann auch sehr schnell klar, wie komplex und übersichtlich das ganze werden kann. Auch gibt es unter MySQL dann das Problem, dass man auf 61 Attribute begrenzt ist, da soweit ich das noch im Kopf habe MySQL maximal 61 Joins je Abfrage unterstützt. (https://dev.mysql.com/doc/refman/5.7...ns-limits.html)
              Für die Umsetzung in der gezeigten Weise braucht man weder JOINS noch mehr als x Attribute pro Tabelle. Lediglich die Zahl der Spalten einer Abfrage sollte nicht begrenzt sein.

              Allerdings: Hier muß man sich dann nochmal auf das Prinzip und den Grund des Einsatzes besinnen. Der besteht ja darin, daß man nur eine geringe Anzahl an Attributen braucht.
              Auch das suchen in solchen EAV Modellen ist relativ aufwendig wie ich finde.
              Das ist das am wenigsten aufwändige, weil es im Falle eines einzelnen Attributs mit
              Code:
              SELECT `AdresseID_FK` FROM `tbl_adresse_eav` WHERE `AttributName` = "Nachname" AND `Wert` = "Müller";
              statt
              Code:
              SELECT `AdresseID` FROM `tbl_adresse` WHERE `Nachname` = "Müller";
              ruckzuck erledigt ist. Im Falle von mehrere Attributen dann eben mit der in #1 gezeigten Lösung, ergänzt um den WHERE-Clause wie oben.

              Insgesamt geht es m.E. darum, den "Wald trotz der vielen Bäumen noch zu sehen"! Sinnvoll ist der Einsatz m.E. in Kombination mit einer "konventionellen" Tabelle. Mit "konventionell" ist in diesem Zus. eine dem relationalen Modell entsprechende Tabelle gemeint, die die häufig für alle Objekte notwendigen Attribute enthält.

              Diese Kombination ist ohne weiteres möglich.

              Schön wäre es, wenn man eine Funktion hätte, in die man als Parameter einen "Pseudo-SQL" eingibt, und "hinten" kommt der SQL-code für die fertige Abfrage raus. Um das Performance-Problem handhabbar zu machen, sollte man aber m.E. eine "Objekt-für-Objekt"-Bearbeitung bevorzugen, die die Daten in einer (temporären) Tabelle speichert. Die kann man dann nachts laufen lassen und am nächsten morgen schaut man nach, wieviele Objekte fertig sind und ob die, die man unbedingt braucht, dabei sind. Zwischen 5 Uhr und 7 Uhr morgens, wenn die Daten benötigt werden, sollten da nicht allzu viele Aktualisierung-Anomalien drin sein... Es muß ja nicht immer alles in einer einzigen SQL-Abfrage bzw. Transaktion geschehen.

              Kommentar


              • #8
                FormSets:
                Mit EAV hast du nun die Möglichkeit verschiedene Kombinationen von Attributen zu speichern, ohne deine Datenbank anzupassen. Die logische Erweiterung ist nun, Form/AttributeSets zu ermöglichen, so dass die verschiedenen "Produkte/Entities" auch wissen welche Attribute sie haben. Auto hat: Reifen, Farbe, usw. PC hat CPU Leistung, Gehäusefarbe etc. Farbe kann nun doppelt verwendet werden, einmal beim Typ Auto und einmal beim Typ PC. Um diese Verbindung herzustellen braucht man Form/AttributeSets.
                Auch für erweiterete Typen, wie z.B. SelectBoxen muss irgendwo gespeichert werden, welche Values erlaubt sind...

                In meinen beidens Links von oben, ist dies auch nochmal schön erklärt.

                2. Mehrere Tabellen
                Eigentlich brauchst du sehrwohl mehrere Tabellen, denn ein Integer kann nicht in einem DateTime Feld gespeichert werden etc. Also alle Integer Attribute Values gehören in die eav_data_int Tabelle, alle DateTime Attribute Values in die eav_data_datetime usw.
                Nur so kannst du auch weiterhin alle Vorteile deines Datenbanksystems ausnutzen.

                Kommentar


                • #9
                  Zitat von Zeichen32 Beitrag anzeigen
                  FormSets:
                  Mit EAV hast du nun die Möglichkeit verschiedene Kombinationen von Attributen zu speichern, ohne deine Datenbank anzupassen. Die logische Erweiterung ist nun, Form/AttributeSets...
                  Hättest du das sofort so formuliert oder einfach von "Formularen" gesprochen, hätte ich dich gleich verstanden.

                  Was du dann schreibst, ist so ziemlich für alles richtig, allerdings bezweifle ich, daß ich EAV für Fälle einsetzen würde, wenn in dem Kontext Formulare mit klar definierten Feldern, zulässigen Werten (also: bestimmte Tabellen fungieren als Prüftabellen, die sind meist "konventionell relational" gebaut) verwendet werden.

                  Ich bin halt kein "Fan" von EAV, sondern setze es dort ein, wo es sinnvoll ist, genau wie ich es aus Normalisierungsgrundsätzen heraus anwenden müsste (nicht EAV, sondern Tabellen mit Attribut/Wert-Kombinationen) und trotzdem nicht tue, wie bpsw. bei verschiedenen Typen von Tel.-Verbindungen. Bei "abw. Lieferadressen", "abw. Rechnungsadressen", "abw. Regulierer" usw. dann doch wieder.

                  Je nachdem, wie es halt sinnvoll und geboten ist. (Edit) Ich habe es in meinem ganzen Leben glaube ich erst zweimal eingesetzt, daß letzte mal vor ca. 10 Jahren für eine Anatomie-Datenbank, die ein großer Wurf werden sollte, aber (vielleicht deshalb) nie fertig geworden ist.

                  Im Übrigen: Gab es für das "wissen welche Attribute [ich] habe[ ]" nicht auch noch diese... sag doch... ah: Objektorientierung? ...
                  In meinen beidens Links von oben, ist dies auch nochmal schön erklärt.

                  2. Mehrere Tabellen
                  Eigentlich brauchst du sehrwohl mehrere Tabellen, denn ein Integer kann nicht in einem DateTime Feld gespeichert werden etc. Also alle Integer Attribute Values gehören in die eav_data_int Tabelle, alle DateTime Attribute Values in die eav_data_datetime usw.
                  Nur so kannst du auch weiterhin alle Vorteile deines Datenbanksystems ausnutzen.
                  Ich denke, ich nutze jetzt schon alle Vorteile meines DBMS, deshalb brauche ich ja auch kein PostgreSQL...

                  Aber für die o.g. Zwecke brauchst du natürlich nicht jedesmal eine neue Tabelle. Du mußt nur in der Tabelle "tbl_attribut" den Datentyp drin haben. In der Tabelle, die ich tbl_adresse_eav nenne, mußt du nur für jeden primitiven Datentyp eine Spalte haben, also eigentlich nur zwei für Text und Fließkomma. Es kann ja immer nur einer von beiden sein.

                  Edit: Aber mit vielem hast du Recht. Setzt man das "Prinzip" (was ja keine Ausschließlichkeit beansprucht) ein, wo es Vorteile hat, hat man die Möglichkeit, abzuwägen und sich ggfs. doch dagegen zu entscheiden.

                  Kommentar


                  • #10
                    Im Übrigen: Gab es für das "wissen welche Attribute [ich] habe[ ]" nicht auch noch diese... sag doch... ah: Objektorientierung? ..
                    Ja, aber wenn du schon weißt welche Attribute dein Objekt hat, dann kannst du sie ja auch direkt in der Tabelle anlegen. EAV ist ja gerade dafür gedacht mit unstrukturierten Daten umzugehen, wo du zur Programmierzeit noch nicht weißt welche es gibt und welchen Datentyp sie haben.

                    Schönes Beispiel dafür ist wie ich finde, Produkte in einem Online Shop. Je nach Produktkategorie hast du ganz verschiedene Attribute für die Produkte. Im Frontend ausgeben ist die eine Sache, aber irgendwo möchte der Benutzer sie ja auch einpflegen, meistens im Backend und dort müssen dann Formular generiert werden. Und da möchte der Benutzer Sie bestimmt anlegen können, ohne das er jedes mal den Programmierer beauftragen muss, die jeweilige Produktklasse oder Datenbank anzupassen.

                    Kommentar


                    • #11
                      Zitat von Zeichen32 Beitrag anzeigen

                      Ja, aber wenn du schon weißt welche Attribute dein Objekt hat, dann kannst du sie ja auch direkt in der Tabelle anlegen. EAV ist ja gerade dafür gedacht mit unstrukturierten Daten umzugehen, wo du zur Programmierzeit noch nicht weißt welche es gibt und welchen Datentyp sie haben.
                      Seh ich auch so, vgl. oben.

                      Schönes Beispiel dafür ist wie ich finde, Produkte in einem Online Shop. Je nach Produktkategorie hast du ganz verschiedene Attribute für die Produkte. Im Frontend ausgeben ist die eine Sache, aber irgendwo möchte der Benutzer sie ja auch einpflegen, meistens im Backend und dort müssen dann Formular generiert werden. Und da möchte der Benutzer Sie bestimmt anlegen können, ohne das er jedes mal den Programmierer beauftragen muss, die jeweilige Produktklasse oder Datenbank anzupassen.
                      Jaah... ja, ok. Ich gehe da einfach von anderen Abläufen aus, z.B.:
                      • Der "Programmierer" (du meinst den, der die Webentwicklung für die Anwendung macht, ja?) hat in Abstimmung mit dem Kunden ("Benutzer") nach "bestem Wissen und Gewissen" ein Formular entworfen.
                      • Das Formular kann je nach Produktgruppe anders aussehen (das Thema hatten wir schon mal, Stichwort "Formular unterschiedlich in Abhängigkeit von Eintrag"), fehlt trotzdem ein Feld, gibt es unten eine Möglichkeit Attribut, Einheit, und Wert einzugeben. Mit javascript kommt jeweils eine neue Reihe dazu, wenn etwas in einem der Felder eingetragen wird.
                      • Die "festen" Einträge gehen in die Tabelle tbl_artikel, die "unteren" Einträge gehen direkt Eintrag für Eintrag in die "EAV-Tabelle", hier z.B. tbl_artikel_attrib.
                      In bestimmten Intervallen kann man dann überlegen, ob bestimmte häufige Attribute nicht doch eine Spalte in tbl_artikel "verdienen".

                      Kommentar

                      Lädt...
                      X