So entwerfen Sie eine Produkttabelle für viele Arten von Produkten, bei denen jedes Produkt viele Parameter aufweist

140

Ich habe nicht viel Erfahrung im Tischdesign. Mein Ziel ist es, eine oder mehrere Produkttabellen zu erstellen, die die folgenden Anforderungen erfüllen:

  • Unterstützt viele Arten von Produkten (TV, Telefon, PC, ...). Jede Art von Produkt hat unterschiedliche Parameter, wie z.

    • Telefon hat Farbe, Größe, Gewicht, Betriebssystem ...

    • PC wird CPU, HDD, RAM haben ...

  • Der Parametersatz muss dynamisch sein. Sie können beliebige Parameter hinzufügen oder bearbeiten.

Wie kann ich diese Anforderungen ohne eine separate Tabelle für jede Art von Produkt erfüllen?

Steinherz
quelle

Antworten:

233

Sie haben mindestens diese fünf Optionen zum Modellieren der von Ihnen beschriebenen Typhierarchie:

  • Vererbung einzelner Tabellen: Eine Tabelle für alle Produkttypen mit genügend Spalten, um alle Attribute aller Typen zu speichern. Dies bedeutet viele Spalten, von denen die meisten in einer bestimmten Zeile NULL sind.

  • Vererbung von Klassentabellen : Eine Tabelle für Produkte, in der Attribute gespeichert sind, die allen Produkttypen gemeinsam sind. Dann eine Tabelle pro Produkttyp, in der Attribute gespeichert sind, die für diesen Produkttyp spezifisch sind.

  • Vererbung konkreter Tabellen : Keine Tabelle für allgemeine Produktattribute. Stattdessen eine Tabelle pro Produkttyp, in der sowohl allgemeine Produktattribute als auch produktspezifische Attribute gespeichert sind.

  • Serialisiertes LOB : Eine Tabelle für Produkte, in der Attribute gespeichert sind, die allen Produkttypen gemeinsam sind. In einer zusätzlichen Spalte wird ein BLOB mit halbstrukturierten Daten in XML, YAML, JSON oder einem anderen Format gespeichert. In diesem BLOB können Sie die für jeden Produkttyp spezifischen Attribute speichern. Sie können ausgefallene Designmuster verwenden, um dies zu beschreiben, z. B. Fassade und Andenken. Unabhängig davon, ob Sie einen Blob von Attributen haben, die in SQL nicht einfach abgefragt werden können. Sie müssen den gesamten Blob zurück zur Anwendung holen und dort sortieren.

  • Entity-Attribute-Value : Eine Tabelle für Produkte und eine Tabelle, die Attribute anstelle von Spalten in Zeilen umwandelt. EAV ist kein gültiges Design in Bezug auf das relationale Paradigma, aber viele Leute verwenden es trotzdem. Dies ist das "Eigenschaftenmuster", das in einer anderen Antwort erwähnt wird. Weitere Fallstricke finden Sie in anderen Fragen mit dem eav-Tag auf StackOverflow .

Ich habe mehr darüber in einer Präsentation, Extensible Data Modeling, geschrieben .


Zusätzliche Gedanken zu EAV: Obwohl viele Leute EAV zu bevorzugen scheinen, tue ich das nicht. Es scheint die flexibelste und daher die beste Lösung zu sein. Beachten Sie jedoch das Sprichwort TANSTAAFL . Hier sind einige der Nachteile von EAV:

  • Keine Möglichkeit, eine Spalte obligatorisch zu machen (entspricht NOT NULL).
  • Keine Möglichkeit, SQL-Datentypen zum Überprüfen von Einträgen zu verwenden.
  • Keine Möglichkeit sicherzustellen, dass Attributnamen konsistent geschrieben werden.
  • Es gibt keine Möglichkeit, einen Fremdschlüssel auf die Werte eines bestimmten Attributs zu setzen, z. B. für eine Nachschlagetabelle.
  • Das Abrufen von Ergebnissen in einem herkömmlichen Tabellenlayout ist komplex und teuer, da Sie JOINfür jedes Attribut Folgendes tun müssen, um Attribute aus mehreren Zeilen abzurufen.

Der Grad an Flexibilität, den EAV Ihnen bietet, erfordert Opfer in anderen Bereichen, wodurch Ihr Code wahrscheinlich so komplex (oder schlechter) wird, als es gewesen wäre, um das ursprüngliche Problem auf konventionellere Weise zu lösen.

In den meisten Fällen ist ein solches Maß an Flexibilität nicht erforderlich. In der Frage des OP zu Produkttypen ist es viel einfacher, eine Tabelle pro Produkttyp für produktspezifische Attribute zu erstellen, sodass zumindest für Einträge desselben Produkttyps eine konsistente Struktur erzwungen wird.

Ich würde EAV nur verwenden, wenn jede Zeile möglicherweise einen bestimmten Satz von Attributen haben muss. Wenn Sie eine begrenzte Anzahl von Produkttypen haben, ist EAV übertrieben. Class Table Inheritance wäre meine erste Wahl.


Update 2019: Je mehr Leute JSON als Lösung für das Problem "Viele benutzerdefinierte Attribute" verwenden, desto weniger gefällt mir diese Lösung. Dies macht Abfragen zu komplex, selbst wenn spezielle JSON-Funktionen verwendet werden , um sie zu unterstützen. Das Speichern von JSON-Dokumenten erfordert viel mehr Speicherplatz als das Speichern in normalen Zeilen und Spalten.

Grundsätzlich ist keine dieser Lösungen in einer relationalen Datenbank einfach oder effizient. Die ganze Idee, "variable Attribute" zu haben, widerspricht grundsätzlich der relationalen Theorie.

Es kommt darauf an, dass Sie eine der Lösungen auswählen müssen, auf deren Grundlage Ihre App am wenigsten schlecht ist . Daher müssen Sie wissen, wie Sie die Daten abfragen, bevor Sie ein Datenbankdesign auswählen. Es gibt keine Möglichkeit, eine Lösung auszuwählen, die "am besten" ist, da eine der Lösungen für eine bestimmte Anwendung möglicherweise am besten geeignet ist.

Bill Karwin
quelle
11
@HimalayaGarg Option "4.5" ist wirklich das Gegenteil des ganzen Punktes von Bills Beitrag.
user3308043
2
Im Gegensatz zu MySQL bietet SQL Server umfassende Unterstützung für XML, XPath und XQuery. Für Benutzer von SQL Server ist es daher am besten, zusätzliche Attribute in einer Spalte vom Typ XML zu speichern (Option 4). Auf diese Weise müssen Sie NICHT "den gesamten Blob zurück zur Anwendung holen und dort sortieren". Sie können sogar Indizes für XML-Spalten in SQL Server erstellen.
Delphi.Boy
2
Ich bevorzuge Serialized LOB für meinen Fall. Aber ist es für ORM geeignet? Ich benutze EF.
Mahmood Jenami
@ user2741577, sicher, aber Sie müssen wahrscheinlich benutzerdefinierten Code schreiben, um die Felder unstrukturierter Daten aus dem LOB zu entpacken und sie auf jedes Entitätsfeld Ihres ORM-Objekts anzuwenden. Ich kenne EF nicht, aber ich nehme an, Sie könnten eine Basis-ORM-Klasse erstellen, die dies tut. Sie müssen verfolgen, welche Felder aus konkreten Feldern der Datenbankzeile stammen und welche Felder aus Feldern des LOB stammen, damit Sie ein LOB neu bilden können, wenn das Objekt gespeichert werden muss.
Bill Karwin
12

@Steinherz

Ich würde den ganzen Weg mit EAV und MVC hierher fahren.

@ Bill Karvin

Hier sind einige der Nachteile von EAV:

  • Keine Möglichkeit, eine Spalte obligatorisch zu machen (entspricht NOT NULL).
  • Keine Möglichkeit, SQL-Datentypen zum Überprüfen von Einträgen zu verwenden.
  • Keine Möglichkeit sicherzustellen, dass Attributnamen konsistent geschrieben werden.
  • Es gibt keine Möglichkeit, einen Fremdschlüssel auf die Werte eines bestimmten Attributs zu setzen, z. B. für eine Nachschlagetabelle.

All diese Dinge, die Sie hier erwähnt haben:

  • Datenvalidierung
  • Rechtschreibprüfung für Attributnamen
  • obligatorische Spalten / Felder
  • Umgang mit der Zerstörung abhängiger Attribute

Meiner Meinung nach gehören sie überhaupt nicht in eine Datenbank, da keine der Datenbanken in der Lage ist, diese Interaktionen und Anforderungen auf einer angemessenen Ebene zu verarbeiten, wie dies eine Programmiersprache einer Anwendung tut.

Meiner Meinung nach ist die Verwendung einer Datenbank auf diese Weise wie die Verwendung eines Steins zum Hämmern eines Nagels. Sie können es mit einem Stein machen, aber sollten Sie nicht einen Hammer verwenden, der präziser und speziell für diese Art von Aktivität entwickelt wurde?

Das Abrufen von Ergebnissen in einem herkömmlichen Tabellenlayout ist komplex und teuer, da Sie für jedes Attribut JOIN ausführen müssen, um Attribute aus mehreren Zeilen abzurufen.

Dieses Problem kann gelöst werden, indem Sie nur wenige Abfragen zu Teildaten durchführen und diese mit Ihrer Anwendung zu einem tabellarischen Layout verarbeiten. Selbst wenn Sie über 600 GB Produktdaten verfügen, können Sie diese stapelweise verarbeiten, wenn Sie Daten aus jeder einzelnen Zeile in dieser Tabelle benötigen.

Weiter gehen Wenn Sie die Leistung der Abfragen verbessern möchten, können Sie bestimmte Vorgänge auswählen, z. B. Berichterstellung oder globale Textsuche, und Indextabellen vorbereiten, in denen die erforderlichen Daten gespeichert und regelmäßig neu generiert werden, beispielsweise alle 30 Minuten.

Sie müssen sich nicht einmal um die Kosten für zusätzlichen Datenspeicher kümmern, da dieser von Tag zu Tag billiger wird.

Wenn Sie immer noch mit der Leistung der von der Anwendung ausgeführten Vorgänge befasst sind, können Sie Erlang, C ++ und Go Language jederzeit verwenden, um die Daten vorzuverarbeiten und später nur die optimierten Daten in Ihrer Hauptanwendung weiter zu verarbeiten.

Pawel Barcik
quelle
you can always use Erlang, C++, Go Language to pre-process the dataWas hast du gemeint? Verwenden Sie anstelle von DB Go lang? Könnten Sie das bitte näher erläutern?
Grün
1
Ich bin vollkommen einverstanden. EAV ist ein guter Weg, insbesondere wenn Sie ein Maß an Flexibilität benötigen, mit dem Sie neue Arten von Produkten und Parametern ohne Änderungen des Datenbankschemas hinzufügen können. Ich meine, Sie können über Ihre Anwendung in der Produktion leben. Kenne ich schon. Hat für mich gearbeitet. Über langsame Abfragen ... hat hier schon jemand von Caches gehört? ;)
pawel.kalisz
@Green Ich habe den letzten Absatz bearbeitet, um es klarer zu machen, aber es geht darum, Ihre EAV-Rohdaten an einen Prozess in einer Sprache zu übergeben, die Datentransformationen, Suchvorgänge in einer Baumstruktur oder grundlegende Kartenreduzierungsvorgänge sehr schnell und schnell verarbeiten kann speichereffizient. Die Einzelheiten hier würden davon abhängen, was optimiert werden muss
Pawel Barcik
6

Wenn ich Class Table InheritanceBedeutung benutze :

Eine Tabelle für Produkte, in der Attribute gespeichert sind, die allen Produkttypen gemeinsam sind. Dann eine Tabelle pro Produkttyp, in der Attribute gespeichert sind, die für diesen Produkttyp spezifisch sind. -Bill Karwin

Was mir am besten an den Vorschlägen von Bill Karwin gefällt. Ich kann einen Nachteil vorhersehen, den ich zu erklären versuchen werde, um zu verhindern, dass er zum Problem wird.

Welchen Notfallplan sollte ich haben, wenn ein Attribut, das nur einem Typ gemeinsam ist, dann zwei, dann drei usw. gemeinsam wird?

Zum Beispiel: (Dies ist nur ein Beispiel, nicht mein eigentliches Problem)

Wenn wir Möbel verkaufen, verkaufen wir möglicherweise Stühle, Lampen, Sofas, Fernseher usw. Der TV-Typ ist möglicherweise der einzige Typ, den wir führen und der einen Stromverbrauch hat. Also würde ich das power_consumptionAttribut auf die setzen tv_type_table. Aber dann fangen wir an, Heimkinosysteme zu tragen, die auch eine power_consumptionEigenschaft haben. OK, es ist nur ein weiteres Produkt, daher füge ich dieses Feld ebenfalls hinzu, stereo_type_tableda dies an dieser Stelle wahrscheinlich am einfachsten ist. Aber im Laufe der Zeit, als wir anfangen, immer mehr Elektronik zu transportieren, stellen wir fest, dass diese power_consumptionbreit genug ist, um in der main_product_table. Was sollte ich jetzt tun?

Fügen Sie das Feld zum hinzu main_product_table. Schreiben Sie ein Skript, um die Elektronik zu durchlaufen, und geben Sie jeweils den richtigen Wert type_tablein die ein main_product_table. Dann lassen Sie diese Spalte von jeder fallen type_table.

Wenn ich immer dieselbe GetProductDataKlasse verwendet habe, um mit der Datenbank zu interagieren und die Produktinformationen abzurufen; Wenn Änderungen am Code jetzt überarbeitet werden müssen, sollten sie nur für diese Klasse gelten.

JD Isaacks
quelle
3

Sie können eine Produkttabelle und eine separate ProductAdditionInfo-Tabelle mit 3 Spalten haben: Produkt-ID, zusätzlicher Info-Name, zusätzlicher Info-Wert. Wenn Farbe von vielen, aber nicht allen Arten von Produkten verwendet wird, kann dies eine nullbare Spalte in der Produkttabelle sein oder einfach in ProductAdditionalInfo eingefügt werden.

Dieser Ansatz ist keine traditionelle Technik für eine relationale Datenbank, aber ich habe gesehen, dass er in der Praxis häufig verwendet wird. Es kann flexibel sein und eine gute Leistung haben.

Steve Yegge nennt dies das Eigenschaftenmuster und schrieb einen langen Beitrag über die Verwendung.

RossFabricant
quelle
4
Das Eigenschaftenmuster ist nur ein Entitätsattributwert mit einem anderen Namen. Es ist weit verbreitet, aber das Speichern in einer relationalen Datenbank verstößt gegen die Normalisierungsregeln.
Bill Karwin
2
Um ehrlich zu sein, als ich die Beschreibung von EAV in der Antwort von @Bills las, verstand ich nicht ganz, was er erklärte. Aber als Sie sagten, 3 columns: product ID, additional info name, additional info valueich habe das Konzept verstanden. Und ich habe das schon einmal gemacht und bin auf Probleme gestoßen. Ich erinnere mich jedoch im Moment nicht, was diese Probleme waren.
JD Isaacks
1
@JDIsaacks In diesem Muster besteht ein häufiges Problem darin, dass wir nicht wissen, wie viele JOINs wir benötigen, um alle Attribute abzurufen.
Omid