Hat jemand Erfahrung mit dem Speichern von Schlüssel-Wert-Paaren in einer Datenbank?
Ich habe diese Art von Tabelle verwendet:
CREATE TABLE key_value_pairs (
itemid varchar(32) NOT NULL,
itemkey varchar(32) NOT NULL,
itemvalue varchar(32) NOT NULL,
CONSTRAINT ct_primarykey PRIMARY KEY(itemid,itemkey)
)
Dann könnten zum Beispiel die folgenden Zeilen existieren:
itemid itemkey itemvalue
---------------- ------------- ------------
123 Colour Red
123 Size Medium
123 Fabric Cotton
Das Problem bei diesem Schema ist, dass die zum Extrahieren von Daten erforderliche SQL-Syntax recht komplex ist. Wäre es besser, nur eine Reihe von Schlüssel- / Wertespalten zu erstellen?
CREATE TABLE key_value_pairs (
itemid varchar(32) NOT NULL,
itemkey1 varchar(32) NOT NULL,
itemvalue1 varchar(32) NOT NULL,
itemkey2 varchar(32) NOT NULL,
itemvalue2 varchar(32) NOT NULL,
. . .etc . . .
)
Dies ist einfacher und schneller abzufragen, es fehlt jedoch die Erweiterbarkeit des ersten Ansatzes. Irgendein Rat?
Antworten:
Bevor Sie Ihren Ansatz fortsetzen, würde ich Ihnen demütig vorschlagen, einen Schritt zurückzutreten und zu überlegen, ob Sie diese Daten wirklich in einer "Schlüssel-Wert-Paar" -Tabelle speichern möchten. Ich kenne Ihre Anwendung nicht, aber meine Erfahrung hat gezeigt, dass ich mir jedes Mal, wenn ich das getan habe, was Sie tun, später wünschte, ich hätte eine Farbtabelle, eine Stofftabelle und eine Größentabelle erstellt.
Denken Sie an referenzielle Integritätsbeschränkungen. Wenn Sie den Schlüssel-Wert-Paar-Ansatz verwenden, kann die Datenbank Ihnen nicht sagen, wann Sie versuchen, eine Farb-ID in einem Größenfeld zu speichern
Denken Sie an die Leistungsvorteile des Beitritts zu einer Tabelle mit 10 Werten im Vergleich zu einem generischen Wert, der möglicherweise Tausende von Werten in mehreren Domänen enthält. Wie nützlich wird ein Index für den Schlüsselwert wirklich sein?
Normalerweise liegt der Grund für das, was Sie tun, darin, dass die Domänen "benutzerdefinierbar" sein müssen. Wenn dies der Fall ist, werde auch ich Sie nicht dazu drängen, Tabellen im laufenden Betrieb zu erstellen (obwohl dies ein praktikabler Ansatz ist).
Wenn Sie jedoch der Meinung sind, dass die Verwaltung einfacher ist als bei mehreren Tabellen oder weil Sie sich eine Wartungsbenutzeroberfläche vorstellen, die für alle Domänen generisch ist, sollten Sie innehalten und gründlich überlegen, bevor Sie fortfahren.
quelle
Es gibt eine andere Lösung, die irgendwo zwischen den beiden liegt. Sie können eine Spalte vom Typ XML für die Schlüssel und Werte verwenden. Sie behalten also das Feld itemid bei und haben dann ein XML-Feld, das die für einige Schlüsselwertpaare definierte XML enthält.
<items> <item key="colour" value="red"/><item key="xxx" value="blah"/></items>
Wenn Sie dann Ihre Daten aus der Datenbank extrahieren, können Sie die XML auf verschiedene Arten verarbeiten. Abhängig von Ihrer Nutzung. Dies ist eine erweiterbare Lösung.quelle
In den meisten Fällen würden Sie die erste Methode verwenden, weil Sie sich nicht wirklich hingesetzt und Ihr Modell durchdacht haben. "Nun, wir wissen noch nicht, wie die Schlüssel aussehen werden". Im Allgemeinen ist dies ein ziemlich schlechtes Design. Es wird langsamer sein, als Ihre Schlüssel tatsächlich als Spalten zu haben, was sie sein sollten.
Ich würde auch fragen, warum Ihre ID ein Varchar ist.
In dem seltenen Fall, dass Sie wirklich eine Schlüssel- / Wertetabelle implementieren müssen, ist die erste Lösung in Ordnung, obwohl ich die Schlüssel im Allgemeinen in einer separaten Tabelle haben möchte, damit Sie Varchars nicht als Schlüssel in Ihrem Schlüssel / speichern. Wertetabelle.
z.B,
CREATE TABLE valid_keys ( id NUMBER(10) NOT NULL, description varchar(32) NOT NULL, CONSTRAINT pk_valid_keys PRIMARY KEY(id) ); CREATE TABLE item_values ( item_id NUMBER(10) NOT NULL, key_id NUMBER(10) NOT NULL, item_value VARCHAR2(32) NOT NULL, CONSTRAINT pk_item_values PRIMARY KEY(item_id), CONSTRAINT fk_item_values_iv FOREIGN KEY (key_id) REFERENCES valid_keys (id) );
Sie können dann sogar verrückt werden und den Schlüsseln einen "TYP" hinzufügen, um eine Typprüfung zu ermöglichen.
quelle
Ich habe einmal Schlüssel-Wert-Paare in einer Datenbank verwendet, um eine Tabelle (zur Dateneingabe) zu erstellen, in der ein Kassierer seine Aktivitäten aus der Arbeit an einer Kassenschublade zusammenfasst. Jedes k / v-Paar stellte eine benannte Zelle dar, in die der Benutzer einen Geldbetrag eingegeben hatte. Der Hauptgrund für diesen Ansatz ist, dass sich die Tabelle stark geändert hat. Neue Produkte und Dienstleistungen wurden routinemäßig hinzugefügt (daher erschienen neue Zellen). Außerdem wurden bestimmte Zellen in bestimmten Situationen nicht benötigt und konnten fallen gelassen werden.
Die App, die ich geschrieben habe, war eine Neufassung einer Anwendung, die das Kassiererblatt in separate Abschnitte unterteilt hat, die jeweils in einer anderen Tabelle dargestellt sind. Das Problem hierbei war, dass beim Hinzufügen von Produkten und Dienstleistungen Schemaänderungen erforderlich waren. Wie bei allen Designentscheidungen gibt es Vor- und Nachteile, eine bestimmte Richtung im Vergleich zu einer anderen einzuschlagen. Mein Redesign hat sicherlich langsamer und schneller Speicherplatz verbraucht. Es war jedoch sehr agil und ermöglichte das Hinzufügen neuer Produkte und Dienstleistungen innerhalb von Minuten. Das einzige Problem war jedoch der Festplattenverbrauch. Es gab keine anderen Kopfschmerzen, an die ich mich erinnern kann.
Wie bereits erwähnt, ist der Grund, warum ich normalerweise einen Schlüssel-Wert-Paar-Ansatz in Betracht ziehe, der, wenn Benutzer - dies könnte der Geschäftsinhaber sein - ihre eigenen Typen mit benutzerspezifischen Attributen erstellen möchten. In solchen Situationen bin ich zu folgender Feststellung gekommen.
Wenn entweder keine Daten über diese Attribute abgerufen werden müssen oder die Suche nach dem Abrufen eines Datenblocks auf die Anwendung verschoben werden kann, empfehle ich, alle Attribute in einem einzigen Textfeld zu speichern (mithilfe von JSON, YAML, XML usw.). ). Wenn es dringend erforderlich ist, Daten anhand dieser Attribute abzurufen, wird dies unübersichtlich.
Sie können eine einzelne "Attribut" -Tabelle (ID, Element-ID, Schlüssel, Wert, Datentyp, Sortierwert) erstellen, in der die Sortierspalte den tatsächlichen Wert in eine nach Zeichenfolgen sortierbare Darstellung umwandelt. (zB Datum: "2010-12-25 12:00:00", Nummer: "0000000001") Oder Sie können separate Attributtabellen nach Datentyp erstellen (z. B. string_attributes, date_attributes, number_attributes). Unter zahlreichen Vor- und Nachteilen beider Ansätze: Der erste ist einfacher, der zweite ist schneller. Beides führt dazu, dass Sie hässliche, komplexe Abfragen schreiben.
quelle
Aus Erfahrung habe ich festgestellt, dass bestimmte Schlüssel häufiger verwendet oder abgefragt werden. Normalerweise haben wir das Design dann leicht de-normalisiert, um ein bestimmtes Feld wieder in die Haupttabelle "item" aufzunehmen.
z.B. Wenn jedes Element eine Farbe hat, können Sie die Spalte Farbe zu Ihrer Elementtabelle hinzufügen. Stoff und Größe werden möglicherweise seltener verwendet und können in der Schlüssel-Wert-Paartabelle getrennt gehalten werden. Sie können die Farbe sogar in der Schlüssel-Wert-Paartabelle behalten, aber die Daten in der Elementtabelle duplizieren, um die Leistungsvorteile zu erzielen.
Dies hängt natürlich von den Daten ab und davon, wie flexibel die Schlüssel-Wert-Paare sein müssen. Dies kann auch dazu führen, dass Ihre Attributdaten nicht konsistent gefunden werden. Durch die De-Normalisierung werden die Abfragen jedoch erheblich vereinfacht und ihre Leistung verbessert.
Normalerweise würde ich eine De-Normalisierung nur in Betracht ziehen, wenn die Leistung zu einem Problem wird, und nicht nur, um eine Abfrage zu vereinfachen.
quelle
PostgreSQL 8.4 unterstützt den Datentyp hstore zum Speichern von Sätzen von (Schlüssel-, Wert-) Paaren in einem einzelnen PostgreSQL-Datenfeld. Informationen zur Verwendung finden Sie unter http://www.postgresql.org/docs/8.4/static/hstore.html . Obwohl es eine sehr alte Frage ist, dachte ich, diese Informationen weiterzugeben, weil ich dachte, sie könnten jemandem helfen.
quelle
Ich denke, der beste Weg, solche Tabellen zu entwerfen, ist wie folgt:
Wichtige Punkte:
quelle
Ich verstehe nicht, warum das SQL zum Extrahieren von Daten für Ihr erstes Design komplex sein sollte. Um alle Werte für einen Artikel zu erhalten, gehen Sie einfach wie folgt vor:
SELECT itemkey,itemvalue FROM key_value_pairs WHERE itemid='123';
oder wenn Sie nur einen bestimmten Schlüssel für diesen Artikel möchten:
SELECT itemvalue FROM key_value_pairs WHERE itemid='123' AND itemkey='Fabric';
Das erste Design bietet Ihnen auch die Flexibilität, jederzeit neue Schlüssel hinzuzufügen.
quelle
Die erste Methode ist ganz ok. Sie können eine UDF erstellen, die die gewünschten Daten extrahiert, und diese einfach aufrufen.
quelle
Wenn Sie nur sehr wenige mögliche Schlüssel haben, würde ich sie nur als Spalten speichern. Wenn der Satz möglicher Schlüssel jedoch groß ist, ist Ihr erster Ansatz gut (und der zweite Ansatz wäre unmöglich).
Oder ist es so, dass jeder Gegenstand nur eine endliche Anzahl von Schlüsseln haben kann, aber die Schlüssel könnten etwas aus einem großen Satz sein?
Sie können auch einen Object Relational Mapper verwenden, um die Abfrage zu vereinfachen.
quelle
Die erste Methode ist zu den von Ihnen genannten Kosten viel flexibler.
Und der zweite Ansatz ist niemals realisierbar, wie Sie gezeigt haben. Stattdessen würden Sie dies tun (gemäß Ihrem ersten Beispiel).
create table item_config (item_id int, colour varchar, size varchar, fabric varchar)
Dies funktioniert natürlich nur, wenn die Datenmenge bekannt ist und sich nicht viel ändert.
In der Regel sollte jeder Anwendung, die das Ändern der DDL von Tabellen für normale Arbeiten erfordert, ein zweiter und ein dritter Gedanke gegeben werden.
quelle
Ein Verstoß gegen die Normalisierungsregeln ist in Ordnung, solange die Geschäftsanforderungen noch erfüllt werden können. Haben
key_1, value_1, key_2, value_2, ... key_n, value_n
kann in Ordnung sein, bis zu dem Punkt, den Sie brauchenkey_n+1, value_n+1
.Meine Lösung war eine Datentabelle für gemeinsam genutzte Attribute und XML für eindeutige Attribute. Das heißt, ich benutze beide. Wenn alles (oder die meisten Dinge) eine Größe haben, ist Größe eine Spalte in der Tabelle. Wenn nur Objekt A das Attribut Z hat, wird Z als XML gespeichert, ähnlich der bereits gegebenen Antwort von Peter Marshall.
quelle
Die zweite Tabelle ist stark de-normalisiert. Ich würde beim ersten Ansatz bleiben.
quelle
Ich denke, Sie tun das Richtige, solange sich die Schlüssel / Werte für einen bestimmten Elementtyp häufig ändern.
Wenn sie eher statisch sind, ist es sinnvoller, die Artikeltabelle einfach breiter zu machen.
Wir verwenden einen ähnlichen (aber etwas komplexeren) Ansatz mit viel Logik um die Schlüssel / Werte sowie Tabellen für die für jeden Schlüssel zulässigen Wertetypen.
Auf diese Weise können wir Elemente als eine weitere Instanz eines Schlüssels definieren, und unsere zentrale Tabelle ordnet beliebige Schlüsseltypen anderen beliebigen Schlüsseltypen zu. Es kann Ihr Gehirn schnell in Knoten binden, aber sobald Sie die Logik geschrieben und gekapselt haben, um alles zu handhaben, haben Sie viel Flexibilität.
Ich kann bei Bedarf weitere Einzelheiten darüber schreiben, was wir tun.
quelle
Wenn die Schlüssel dynamisch sind oder viele davon vorhanden sind, verwenden Sie die Zuordnungstabelle, die Sie als erstes Beispiel haben. Darüber hinaus ist dies die allgemeinste Lösung. Sie lässt sich in Zukunft am besten skalieren, wenn Sie mehr Schlüssel hinzufügen. Es ist einfach, SQL zu codieren, um die Daten herauszuholen, und die Datenbank kann die Abfrage besser optimieren, als Sie sich vorstellen ( Das heißt, ich würde mich nicht bemühen, diesen Fall vorzeitig zu optimieren, es sei denn, es würde sich später als Engpass beim Testen herausstellen. In diesem Fall könnten Sie die nächsten beiden Optionen in Betracht ziehen.
Wenn die Schlüssel eine bekannte Menge sind und es nicht viele davon gibt (<10, vielleicht <5), sehe ich das Problem nicht darin, sie als Wertespalten auf dem Element zu haben.
Wenn es eine mittlere Anzahl bekannter fester Schlüssel gibt (10 - 30), haben Sie möglicherweise eine andere Tabelle, in der die item_details gespeichert sind.
Ich sehe jedoch nie die Notwendigkeit, Ihre zweite Beispielstruktur zu verwenden, sie sieht umständlich aus.
quelle
Wenn Sie den Weg einer KVP-Tabelle gehen und ich muss sagen, dass mir diese Technik selbst überhaupt nicht gefällt, da es in der Tat schwierig ist, sie abzufragen, sollten Sie in Betracht ziehen, die Werte für eine einzelne Element-ID mithilfe einer geeigneten Technik zu gruppieren für welche Plattform auch immer Sie sich befinden.
RDBMS neigen dazu, Zeilen zu verteilen, um Blockkonflikte bei Einfügungen zu vermeiden. Wenn Sie 8 Zeilen abrufen müssen, können Sie leicht auf 8 Blöcke der Tabelle zugreifen, um sie zu lesen. Unter Oracle sollten Sie einen Hash-Cluster zum Speichern dieser in Betracht ziehen, der die Leistung beim Zugriff auf die Werte für eine bestimmte Element-ID erheblich verbessern würde.
quelle
Ihr Beispiel ist kein sehr gutes Beispiel für die Verwendung von Schlüsselwertpaaren. Ein besseres Beispiel wäre die Verwendung einer Gebührentabelle, einer Kundentabelle und einer Customer_Fee-Tabelle in einer Abrechnungsanwendung. Die Gebührentabelle würde aus Feldern bestehen wie: fee_id, fee_name, fee_description Die Customer_Fee-Tabelle würde aus Feldern bestehen wie: customer_id, fee_id, fee_value
quelle
Die Zeiten haben sich geändert. Jetzt haben Sie andere Datenbanktypen, die Sie neben relationalen Datenbanken verwenden können. Zu den NOSQL-Optionen gehören jetzt Spaltenspeicher, Dokumentenspeicher, Diagramme und Multi-Modelle (siehe: http://en.wikipedia.org/wiki/NoSQL ).
Bei Schlüsselwertdatenbanken können Sie unter anderem CouchDb, Redis und MongoDB auswählen (ohne darauf beschränkt zu sein).
quelle