it-swarm.com.de

Gibt es einen Namen für dieses Datenbankschema mit Schlüsselwerten?

Wir verarbeiten einen routinemäßigen Datenfeed von einem Client, der gerade seine Datenbank von einem vertrauten Formular (eine Zeile pro Entität, eine Spalte pro Attribut) zu einem mir unbekannten Dokument (eine Zeile pro Entität pro Attribut) überarbeitet hat:

Vorher: eine Spalte pro Attribut

ID   Ht_cm   wt_kg   Age_yr  ... 
1      190      82     43    ...
2      170      60     22    ...
3      205      90     51    ...

Nachher: ​​eine Spalte für alle Attribute

ID    Metric   Value
 1     Ht_cm     190
 1     Wt_kg     82
 1     Age_yr    43
 1      ...
 2     Ht_cm     170
 2     Wt_kg     60
 2     Age_yr    22
 2     ...
 3     Ht_cm     205
 3     Wt_kg     90
 3     Age_yr    51
 3     ...

Gibt es einen Namen für diese Datenbankstruktur? Was sind die relativen Vorteile? Der alte Weg scheint einfacher zu sein, Gültigkeitsbeschränkungen für bestimmte Attribute (nicht null, nicht negativ usw.) festzulegen und Durchschnittswerte einfacher zu berechnen. Aber ich kann sehen, wie es einfacher sein könnte, neue Attribute hinzuzufügen, ohne die Datenbank umzugestalten. Ist dies eine Standard-/bevorzugte Methode zur Strukturierung von Daten?

70
prototype

Es heißt Entity-Attribute-Value (manchmal auch "Name-Wert-Paare") und ist ein klassischer Fall von "einem runden Stift in einem quadratischen Loch", wenn Benutzer das EAV-Muster in einer relationalen Datenbank verwenden.

Hier ist eine Liste, warum Sie EAV nicht verwenden sollten :

  • Sie können keine Datentypen verwenden. Es spielt keine Rolle, ob der Wert ein Datum, eine Zahl oder ein Geld (dezimal) ist. Es wird immer zu Varchar gezwungen werden. Dies kann alles sein, von einem kleinen Leistungsproblem bis zu einem massiven Bauchschmerz (musste jemals eine Abweichung von einem Cent in einem monatlichen Roll-up-Bericht verfolgt werden?).
  • Sie können Einschränkungen nicht (einfach) durchsetzen. Es erfordert eine lächerliche Menge an Code, um "Jeder muss eine Höhe zwischen 0 und 3 Metern haben" oder "Alter darf nicht null und> = 0 sein" durchzusetzen, im Gegensatz zu den 1-2 Zeilen, die jede dieser Einschränkungen sein würde in einem richtig modellierten System.
  • In Bezug auf das oben Gesagte können Sie nicht einfach garantieren, dass Sie die Informationen erhalten, die Sie für jeden Kunden benötigen (das Alter fehlt möglicherweise bei einem Kunden, bei dem nächsten fehlt möglicherweise die Größe usw.). Sie können es tun, aber es ist verdammt viel schwieriger als SELECT height, weight, age FROM Client where height is null or weight is null.
  • Auch hier ist es viel schwieriger, doppelte Daten zu erkennen (was passiert, wenn Sie für einen Client zwei Altersstufen erhalten? Wenn Sie die Daten wie unten beschrieben deaktivieren, erhalten Sie zwei Ergebniszeilen, wenn Sie ein Attribut verdoppelt haben. Wenn ein Client doppelt vorhanden ist Wenn Sie zwei separate Einträge für zwei Attribute haben, erhalten Sie vier Zeilen aus der folgenden Abfrage.
  • Sie können nicht einmal garantieren, dass die Attributnamen konsistent sind. "Age_yr" kann zu "AGE_IN_YEARS" oder "age" werden. (Zugegeben, dies ist weniger problematisch, wenn Sie einen Auszug erhalten, als wenn Personen Daten einfügen, aber immer noch.)
  • Jede Art von nicht trivialer Abfrage ist eine völlige Katastrophe. Um ein EAV-System mit drei Attributen so zu relationalisieren, dass Sie es rational abfragen können, sind drei Verknüpfungen der EAV-Tabelle erforderlich.

Vergleichen Sie:

SELECT cID.ID AS [ID], cH.Value AS [Height], cW.Value AS [Weight], cA.Value AS [Age]
FROM (SELECT DISTINCT ID FROM Client) cID 
      LEFT OUTER JOIN 
    Client cW ON cID.ID = cW.ID AND cW.Metric = "Wt_kg" 
      LEFT OUTER JOIN 
    Client cH ON cID.ID = cH.ID AND cW.Metric = "Ht_cm" 
      LEFT OUTER JOIN 
    Client cA ON cID.ID = cA.ID AND cW.Metric = "Age_yr"

Zu:

SELECT c.ID, c.Ht_cm, c.Wt_kg, c.Age_yr
FROM Client c

Hier ist eine (sehr kurze) Liste, wann Sie EAV verwenden sollten :

  • Wenn absolut kein Weg daran vorbei ist und Sie schemalose Daten in Ihrer Datenbank unterstützen müssen.
  • Wenn Sie nur "Zeug" speichern müssen und nicht erwarten, dass Sie es in einer strukturierteren Form benötigen. Passen Sie jedoch auf, dass das Monster "sich ändernde Anforderungen" nennt.

Ich weiß, ich habe gerade diesen ganzen Beitrag damit verbracht, zu beschreiben, warum EAV in den meisten Fällen eine schreckliche Idee ist - aber es gibt einige Fälle, in denen dies erforderlich/unvermeidbar ist. Meistens (einschließlich des obigen Beispiels) wird es jedoch weitaus mühsamer sein, als es wert ist. Wenn Sie eine umfassende Unterstützung der Dateneingabe vom Typ EAV benötigen, sollten Sie diese in einem Schlüsselwertsystem speichern, z. Hadoop/HBase, CouchDB, MongoDB, Cassandra, BerkeleyDB.

95
Simon Righarts

Entitätsattributwert (EAV)

Es wird von vielen, einschließlich mir, als Anti-Muster angesehen.

Hier sind Ihre Alternativen:

  1. datenbank verwenden Tabellenvererbung

  2. verwenden Sie XML-Daten und SQLXML-Funktionen

  3. verwenden Sie eine NOSQL-Datenbank wie HBase

19
Neil McGuigan

In PostgreSQL ist eine sehr gute Möglichkeit, mit EAV-Strukturen umzugehen, das zusätzliche Modul hstore , das für verfügbar ist Version 8.4 oder höher. Ich zitiere das Handbuch:

Dieses Modul implementiert den Datentyp hstore zum Speichern von Sätzen von Schlüssel/Wert-Paaren in einem einzelnen PostgreSQL-Wert. Dies kann in verschiedenen Szenarien hilfreich sein, z. B. in Zeilen mit vielen Attributen, die nur selten untersucht werden, oder in halbstrukturierten Daten. Schlüssel und Werte sind einfach Textzeichenfolgen.

Seit Postgres 9.2 gibt es auch den Typ json und einen dazugehörigen Funktionshost (- das meiste davon mit 9.3 hinzugefügt ).

Postgres 9.4 fügt der Liste von den (weitgehend überlegenen!) "Binären JSON" -Datentyp jsonb hinzu Optionen. Mit erweiterten Indexoptionen.

16

Es ist lustig zu sehen, wie das EAV-DB-Modell von einigen kritisiert und sogar als "Anti-Pattern" angesehen wird.

Für mich sind die Hauptnachteile:

  • Lernkurve ist steiler wenn Sie an einem Projekt teilnehmen, das bereits vor einiger Zeit mit EAV begonnen hat. In der Tat die Abfragen sind schwierig, da Sie die Anzahl der Verknüpfungen (und Tabellen) erheblich erhöhen und Sie mehr Zeit zum Verstehen benötigen. Schauen Sie sich einfach das Magento-Projekt an und sehen Sie, wie schwer es den Entwicklern außerhalb des Projekts fällt, an der Datenbank zu arbeiten, aber die Dokumentation ist gut erhalten.
  • Nicht für die Berichterstellung geeignet, wenn Sie die Anzahl der Personen ermitteln möchten, deren Name mit "M" usw. beginnt ...

Sie sollten diese Lösung jedoch auf keinen Fall verwerfen. Hier ist der Grund:

  • Simon sprach über das Monster namens "Ändern der Anforderungen". Ich mag diesen Ausdruck :). Und meiner Meinung nach ist EAV genau deshalb ein guter Kandidat, denn dies ist gut geeignet für "Änderung", da Sie ganz einfach so viele Attribute hinzufügen können, wie Sie möchten. Natürlich hängt es von den Anforderungen ab, die wir ändern. Wenn es sich um ein ganz neues Geschäft handelt, müssen Sie natürlich Ihr dataModel überprüfen, aber EAV bietet viel Flexibilität. Nur weil es nach mehr Strenge verlangt, heißt das nicht, dass dies weniger interessant ist.
  • Es wurde auch gesagt, dass "Sie keine Datentypen verwenden können." : Das ist falsch. Möglicherweise haben Sie mehrere Wertetabellen, eine für jeden Datentyp. Anschließend müssen Sie in Ihrer Attributtabelle angeben, welche Art von Datentyp Ihr ​​Attribut ist. Tatsächlich bietet eine Mischung aus klassischer Beziehung/EAV und Klassenbeziehung ein großes interessantes Potenzial für das Datenbankdesign.
11

Wenn Sie eine Datenbank haben, die die EAV-Struktur verwendet, können Sie die Daten auf verschiedene Arten abfragen.

@ Simons Antwort zeigt bereits, wie eine Abfrage mit mehreren Joins durchgeführt wird.

Verwendete Beispieldaten:

CREATE TABLE yourtable ([ID] int, [Metric] varchar(6), [Value] int);

INSERT INTO yourtable ([ID], [Metric], [Value])
VALUES (1, 'Ht_cm', 190),
    (1, 'Wt_kg', 82),
    (1, 'Age_yr', 43),
    (2, 'Ht_cm', 170),
    (2, 'Wt_kg', 60),
    (2, 'Age_yr', 22),
    (3, 'Ht_cm', 205),
    (3, 'Wt_kg', 90),
    (3, 'Age_yr', 51);

Wenn Sie ein RDBMS mit der Funktion PIVOT ( SQL Server 2005 + / Oracle 11g + ) verwenden, können Sie die Daten folgendermaßen abfragen:

select id, Ht_cm, Wt_kg, Age_yr
from
(
  select id, metric, value
  from yourtable
) src
pivot
(
  max(value)
  for metric in (Ht_cm, Wt_kg, Age_yr)
) piv;

Siehe SQL Fiddle mit Demo

Wenn Sie keinen Zugriff auf eine PIVOT -Funktion haben, können Sie eine Aggregatfunktion mit einer CASE -Anweisung verwenden, um die Daten zurückzugeben:

select id,
  max(case when metric ='Ht_cm' then value else null end) Ht_cm,
  max(case when metric ='Wt_kg' then value else null end) Wt_kg,
  max(case when metric ='Age_yr' then value else null end) Age_yr
from yourtable
group by id

Siehe SQL Fiddle mit Demo

Beide Abfragen geben Daten im Ergebnis zurück:

| ID | HT_CM | WT_KG | AGE_YR |
-------------------------------
|  1 |   190 |    82 |     43 |
|  2 |   170 |    60 |     22 |
|  3 |   205 |    90 |     51 |
10
Taryn