2009-09-18 3 views
15

Ich habe eine Reihe von verschiedenen Objekten mit einer unterschiedlichen Anzahl von Attributen. Bis jetzt habe ich die Daten in XML-Dateien gespeichert, die leicht eine sich ständig ändernde Anzahl von Attributen ermöglichen. Aber ich versuche, es in eine Datenbank zu verschieben.So speichern Sie Daten mit dynamischer Anzahl von Attributen in einer Datenbank

Wie würden Sie diese Daten am besten speichern?

Einige Strategien, die ich bisher identifiziert:

  • ein einziges Feld mit dem Namen „Attribute“ in der Tabelle des Objekts zu haben und die Daten serialisiert oder dort json'ed.
  • Speichern Sie die Daten in zwei Tabellen (Objekte, Attribute) und verwenden Sie eine dritte, um die Beziehungen zu speichern, so dass es eine echte n: m-Beziehung ist. Sehr saubere Lösung, aber möglicherweise sehr teuer, um ein ganzes Objekt und alle seine Attribute zu erhalten
  • Identifizieren von Attributen, die alle Objekte gemeinsam haben, und das Erstellen von Feldern für diese Objekte in der Tabelle des Objekts. Speichern Sie die verbleibenden Attribute als serialisierte Daten in einem anderen Feld. Dies hat einen Vorteil gegenüber der ersten Strategie und erleichtert die Suche.

Irgendwelche Ideen?

+0

Was ist die Motivation zu einer DB-Lösung für die Bewegung? Sie sagten unten, dass Geschwindigkeit Ihre Hauptsorge ist. Glauben Sie, dass eine db-Lösung schneller ist als Ihr aktueller XML-Ansatz? –

+0

Eine vierte Strategie kam mir bei DVK vor, die dasselbe vorschlug: Speichern allgemeiner Attribute in der Objekttabelle und Speichern aller anderen unter Verwendung einer 1: n-Beziehung einer zweiten Tabelle. Scheint wie der beste Kompromiss für Geschwindigkeit, Flexibilität und saubere Lösung (@ Tobiask) –

+0

@Corey, nein, ich nicht. Die XML-Lösung ist im Moment unglaublich schnell und ich denke nicht, dass eine DB damit Schritt halten könnte. Es ist mehr eine Übung für mich, zu versuchen, das System hinsichtlich der Speicheroptionen flexibler zu machen und gleichzeitig meine MySQL-Fähigkeiten zu verbessern. –

Antwort

18

aktualisieren Wenn Sie jemals Plan für bestimmte attribtes auf der Suche, es ist eine schlechte Idee, serialisieren Sie sie in eine einzelne Spalte, da Sie die Funktionen pro Zeile verwenden müssen, um die Informationen herauszubekommen - das skaliert nie gut.

Ich würde für Ihre zweite Wahl entscheiden. Haben Sie eine Liste von Attributen in einer Attributtabelle, die Objekte in ihrer eigenen Tabelle und eine Viele-zu-Viele-Beziehungstabelle, die als Objektattribute bezeichnet wird.

Zum Beispiel:

objects: 
    object_id integer 
    object_name varchar(20) 
    primary key (object_id) 
attributes: 
    attr_id  integer 
    attr_name varchar(20) 
    primary key (attr_id) 
object_attributes: 
    object_id integer references (objects.object_id) 
    attr_id  integer references (attributes.attr_id) 
    primary key (object_id,attr_id) 

Ihre Sorge über die Leistung ist anzumerken, aber nach meiner Erfahrung ist es immer teurer, eine Spalte zu spalten als mehrere Spalten zu kombinieren. Wenn sich herausstellt, dass es Leistungsprobleme gibt, ist es völlig in Ordnung, 3NF aus Performance-Gründen zu brechen.

In diesem Fall würde ich es auf die gleiche Weise speichern, sondern auch eine Spalte mit den rohen serialisierten Daten haben. Vorausgesetzt, Sie verwenden Trigger zum Einfügen/Aktualisieren, um die Spalten- und kombinierten Daten synchron zu halten, haben Sie keine Probleme. Aber Sie sollten sich darüber keine Gedanken machen, bis ein tatsächliches Problem auftaucht.

Mit diesen Auslösern minimieren Sie die Arbeit, die nur erforderlich ist, wenn sich die Daten ändern. Wenn Sie versuchen, Informationen zur Unterspalte zu extrahieren, müssen Sie nicht bei jeder Auswahl arbeiten.

+0

Genau meine Sorge mit der ersten Strategie. –

+0

die Frage ist, was ist besser für die Leistung Ihrer Methode ist eav, was ist Ihre Meinung über JSON Modellierung von Daten speichern –

+0

@babakfaghihian, ich denke, dass ich das in meinen letzten zwei Absätze, ja? Es ist in Ordnung, 3NF für die Leistung zu brechen, vorausgesetzt, Sie verstehen und mindern die Risiken (der Datenelemente "widersprechen" einander). Das Speichern der Originaldaten (XML, JSON oder was auch immer) ist ein Ansatz dafür. – paxdiablo

1

klingt wie Sie brauchen etwas lecken couchdb, kein RDBMS.

+0

Das klingt nach einer idealen Lösung. Leider habe ich es hauptsächlich mit Szenarien zu tun, in denen ich nicht viel mehr als nur MySQL nutzen kann, geschweige denn eine andere Datenbank auf dem Server zu installieren. –

6

Eine Variation auf Ihrer 2d Lösung ist nur zwei Tabellen (alle Attribute sind aus einem einzigen Typ vorausgesetzt):

T1: | Objektdatenspalten | Object_id |

T2: | Objekt-ID | Attributname | Attributwert | (eindeutiger Index auf den ersten 2 Spalten)

Dies ist noch effizienter, wenn es mit einer dritten Lösung, z. Alle allgemeinen Felder gehen in T1.

Sstuffing> 1 Attribut in das gleiche Blob ist nicht empfohlen - nicht durch Attribute filtern können, Sie nicht effizient sie

+0

Genau das ist mir in den Sinn gekommen, nachdem ich meine drei Strategien noch einmal durchgelesen habe. Klingt wie der beste Weg zu gehen. –

+1

Hallo. Dies nennt man eine Entity-Atribute-Value-Tabelle, und es ist schlechtes Design http://programmers.stackexchange.com/questions/93124/eav-is-it-really-bad-in-all-scenarios –

+0

@GabriBotha - Die Antworten auf die verknüpfte Frage unterstützen in keiner Weise Ihre flache und unausgesprochene Behauptung, dass es ein "schlechtes" Design ist. Es ist ein Design mit spezifischen Fehlern - wie ALLE Designs - und spezifischen Situationen, in denen es der beste Ansatz ist. – DVK

1

Wenn Sie die Attribute in einem späteren Punkt bearbeiten/bearbeiten/löschen wollen, dann ist das richtige n: m (zweite Option) die richtige Wahl. (Oder versuchen Sie, es 2 Tabelle zu machen, in der das selbe Attribut sich wiederholt. Aber Datengröße ist hoch)

Wenn Sie nicht mit Attributen beschäftigen (gerade erfassen und die Daten zeigen), dann können Sie fortfahren und in einem Feld speichern mit einigen Trennzeichen (Stellen Sie sicher, dass das Trennzeichen nicht in dem Attributwert auftritt)

1

Wenn Sie eine relationale Datenbank verwenden, dann denke ich, dass Sie die Optionen gut aufgelistet haben. Sie haben ihre Vor- und Nachteile. Sie sind in der besten Position, um zu entscheiden, was für Ihre Situation am besten ist.

Der serialisierte Ansatz ist wahrscheinlich der schnellste (abhängig von Ihrem Code für das Deserialisieren), aber es bedeutet, dass Sie die Daten nicht mit SQL abfragen können. Wenn Sie sagen, dass Sie die Daten nicht mit SQL abfragen müssen, stimme ich @longneck zu, vielleicht sollten Sie eine Schlüssel/Wert-Stil-Datenbank anstelle einer relationalen Datenbank verwenden.

BEARBEITEN - Lesen Sie mehr Ihrer Kommentare, WARUM schalten Sie auf eine db, wenn Geschwindigkeit Ihre Hauptsorge ist. Was ist an Ihrer aktuellen XML-Implementierung SCHLECHT?

2

verwendete ich this scheme umzusetzen:

t_class (id RAW(16), parent RAW(16)) -- holds class hierachy. 
t_property (class RAW(16), property VARCHAR) -- holds class members. 
t_declaration (id RAW(16), class RAW(16)) -- hold GUIDs and types of all class instances 
t_instance (id RAW(16), class RAW(16), property VARCHAR2(100), textvalue VARCHAR2(200), intvalue INT, doublevalue DOUBLE, datevalue DATE) -- holds 'common' properties 

t_class1 (id RAW(16), amount DOUBLE, source RAW(16), destination RAW(16)) -- holds 'fast' properties for class1. 
t_class2 (id RAW(16), comment VARCHAR2(200)) -- holds 'fast' properties for class2 
--- etc. 

RAW(16) ist, wo OracleGUID

s hält Wenn Sie alle Eigenschaften für ein Objekt auswählen möchten, können Sie ausgeben:

SELECT i.* 
FROM (
     SELECT id 
     FROM t_class 
     START WITH 
       id = (SELECT class FROM t_declaration WHERE id = :object_id) 
     CONNECT BY 
       parent = PRIOR id 
     ) c 
JOIN property p 
ON  p.class = c.id 
LEFT JOIN 
     t_instance i 
ON  i.id = :object_id 
     AND i.class = p.class 
     AND i.property = p.property 

t_property halte Sachen, die du normalerweise nicht suchst (zB Textbeschreibungen etc.)

Schnelle Eigenschaften sind in der Tat normale Tabellen, die Sie in der Datenbank haben, um die Abfragen effizienter zu machen. Sie enthalten Werte nur für die Instanzen einer bestimmten Klasse oder ihrer Nachkommen. Dies dient dazu, zusätzliche Joins zu vermeiden.

Sie müssen keine schnellen Tabellen verwenden und alle Ihre Daten auf diese vier Tabellen beschränken.

+1

Wow, das ist noch einen Schritt weiter. Aber würde das nicht zu einer großen Anzahl von Tabellen führen, wenn Sie für jede Klassenart einen haben? Und Ihre letzte SQL-Anweisung macht mir wirklich Hoffnung, dass das von mir bestellte MySQL-Buch eher früher als später ankommt. –

+1

'@ Jörg': Das war in' Oracle' und das ist 'Oracle'-Syntax. In 'MySQL' müssen Sie diese Funktion auf eine andere Weise implementieren: http://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/ – Quassnoi

+0

Sie müssen Tabellen nur für erstellen " Schnelle Eigenschaften ": wenn Sie einen zusammengesetzten Index für zwei oder mehr Eigenschaften erstellen müssen. Ansonsten können Sie nur 4 Basistabellen haben. – Quassnoi

3

Lassen Sie mich einige Anschaulichkeit geben, was DVK sagte.

Unter der Annahme, Werte gleichen Typs sind in der Tabelle aussehen würde (viel Glück, ich fühle mich Sie werden es brauchen):

 
dynamic_attribute_table 
------------------------ 
id   NUMBER 
key  VARCHAR 
value  SOMETYPE? 

Beispiel (Autos):

 
|id| key | value | 
--------------------------- 
| 1|'Make' |'Ford'  | 
| 1|'Model' |'Edge'  | 
| 1|'Color' |'Blue'  | 
| 2|'Make' |'Chevrolet'| 
| 2|'Model' |'Malibu' | 
| 2|'MaxSpeed'|'110mph' | 

So ,
Einheit 1 = {('Marke', 'Ford'), ('Modell', 'Kante'), ('Farbe', 'Blau')}
und,
Einheit 2 = {('Make "Chevrolet", "Model", "Malibu", "MaxSpeed", "110mph").

+0

Was ist, wenn Sie eine Maschine mit schwarzer Farbe und gelber Farbe sagen möchten? –

Verwandte Themen