Question Comment concevoir une table de produits pour de nombreux types de produits où chaque produit a de nombreux paramètres


Je n'ai pas beaucoup d'expérience dans la conception de tables. Mon objectif est de créer une ou plusieurs tables de produits répondant aux exigences ci-dessous:

  • Soutenir de nombreux types de produits (TV, téléphone, PC, ...). Chaque type de produit a un ensemble de paramètres différent, comme:

    • Le téléphone aura la couleur, la taille, le poids, l'OS ...

    • PC aura CPU, disque dur, RAM ...

  • L'ensemble des paramètres doit être dynamique. Vous pouvez ajouter ou modifier n'importe quel paramètre que vous aimez.

Comment puis-je répondre à ces exigences sans un tableau distinct pour chaque type de produit?


111
2018-03-30 01:19


origine


Réponses:


Vous avez au moins ces cinq options pour modéliser la hiérarchie de types que vous décrivez:

  • Héritage de table unique: une table pour tous les types de produit, avec suffisamment de colonnes pour stocker tous les attributs de tous les types. Ça signifie beaucoup des colonnes, dont la plupart sont NULL sur une ligne donnée.

  • Héritage de table de classe: un tableau pour les produits, stockant les attributs communs à tous les types de produits. Ensuite, un tableau par type de produit, stockant les attributs spécifiques à ce type de produit.

  • Héritage de table en béton: pas de tableau pour les attributs communs des produits. Au lieu de cela, une table par type de produit, stockant à la fois les attributs communs du produit et les attributs spécifiques au produit.

  • Sérialisé LOB: Une table pour les produits, stockant les attributs communs à tous les types de produits. Une colonne supplémentaire stocke un BLOB de données semi-structurées, en XML, YAML, JSON ou dans un autre format. Ce BLOB vous permet de stocker les attributs spécifiques à chaque type de produit. Vous pouvez utiliser des motifs de conception sophistiqués pour décrire cela, tels que Facade et Memento. Mais indépendamment du fait que vous avez un tas d'attributs qui ne peuvent pas être facilement interrogés dans SQL; vous devez récupérer le blob complet dans l'application et le trier.

  • Valeur d'attribut d'entité: Une table pour les produits et une table qui fait pivoter les attributs vers les lignes au lieu des colonnes. L'EAV n'est pas une conception valide par rapport au paradigme relationnel, mais de nombreuses personnes l'utilisent quand même. Ceci est le "modèle de propriétés" mentionné par une autre réponse. Voir d'autres questions avec le tag eav sur StackOverflow pour certains des pièges.

J'en ai écrit plus dans une présentation, Extensible Data Modeling.


Réflexions supplémentaires sur l'EAV: Bien que beaucoup de personnes semblent préférer l'EAV, ce n'est pas le cas. Cela semble être la solution la plus flexible, et donc la meilleure. Cependant, gardez à l'esprit l'adage TANSTAAFL. Voici quelques inconvénients de l'EAV:

  • Aucun moyen de rendre une colonne obligatoire (équivalent de NOT NULL).
  • Aucun moyen d'utiliser des types de données SQL pour valider des entrées.
  • Aucun moyen de s'assurer que les noms d'attribut sont orthographiés de manière cohérente.
  • Pas de moyen de mettre une clé étrangère sur les valeurs d'un attribut donné, par ex. pour une table de consultation.
  • La récupération des résultats dans une présentation tabulaire classique est complexe et coûteuse, car pour obtenir les attributs de plusieurs lignes, vous devez le faire. JOINpour chaque attribut.

Le degré de flexibilité que vous offre EAV exige des sacrifices dans d’autres domaines, rendant probablement votre code aussi complexe (ou pire) qu’il ne l’aurait été pour résoudre le problème initial de manière plus conventionnelle.

Et dans la plupart des cas, il est inutile d'avoir ce degré de flexibilité. Dans la question des OP sur les types de produit, il est beaucoup plus simple de créer une table par type de produit pour les attributs spécifiques au produit. Vous disposez donc d'une structure cohérente au moins pour les entrées du même type de produit.

J'utiliserais EAV seulement si chaque rang doit être autorisé à avoir potentiellement un ensemble distinct d'attributs. Lorsque vous avez un ensemble fini de types de produits, EAV est excessif. Héritage de table de classe serait mon premier choix.


192
2018-03-30 02:41



@Cœur de pierre

Je voudrais aller ici avec EAV et MVC tout le chemin.

@Bill Karvin

Voici quelques inconvénients de   EAV:

No way to make a column mandatory (equivalent of NOT NULL).
No way to use SQL data types to validate entries.
No way to ensure that attribute names are spelled consistently.
No way to put a foreign key on the values of any given attribute, e.g.

pour une table de consultation.

Toutes les choses que vous avez mentionnées ici:

  • la validation des données
  • noms d'attributs validation d'orthographe
  • colonnes / champs obligatoires
  • gérer la destruction des attributs dépendants

à mon avis, n'appartiennent à aucune base de données car aucune des bases de données n'est capable de gérer ces interactions et ces exigences à un niveau approprié, comme le fait le langage de programmation d'une application.

À mon avis, utiliser une base de données de cette manière, c'est comme utiliser une pierre pour marteler un clou. Vous pouvez le faire avec un caillou, mais n'êtes-vous pas supposé utiliser un marteau plus précis et spécifiquement conçu pour ce type d’activité?

La récupération des résultats dans une présentation tabulaire classique est complexe et   cher, car pour obtenir des attributs   à partir de plusieurs lignes, vous devez vous joindre   pour chaque attribut.

Ce problème peut être résolu en effectuant quelques requêtes sur des données partielles et en les traitant sous forme de tableau avec votre application. Même si vous disposez de 600 Go de données produit, vous pouvez les traiter par lots si vous avez besoin de données provenant de chaque ligne de ce tableau.

Aller plus loin Si vous souhaitez améliorer les performances des requêtes, vous pouvez sélectionner certaines opérations, par ex. la création de rapports ou la recherche de texte globale et de leur préparer des tables d’index qui stockent les données requises et sont régénérées périodiquement, disons toutes les 30 minutes.

Vous n'avez même pas besoin de vous soucier du coût du stockage de données supplémentaire, car il devient de moins en moins cher et moins cher chaque jour.

Si vous êtes toujours préoccupé par les performances des opérations effectuées par l'application, vous pouvez toujours utiliser Erlang, C ++, Go Language pour pré-traiter les données et traiter ensuite les données optimisées dans votre application principale.


13
2018-03-21 14:20



Si j'utilise Class Table Inheritance sens:

un tableau pour les produits, stockant les attributs communs à tous les types de produits. Ensuite, un tableau par type de produit, stockant les attributs spécifiques à ce type de produit.   -Bill Karwin

Ce que j'aime le mieux des suggestions de Bill Karwin. Je peux en quelque sorte prévoir un inconvénient, que je vais essayer d'expliquer comment éviter de devenir un problème.

Quel plan d'urgence doit-on mettre en place lorsqu'un attribut commun à 1 type devient commun à 2, puis 3, etc.?

Par exemple: (ceci est juste un exemple, pas mon vrai problème)

Si nous vendons des meubles, nous pourrions vendre des chaises, des lampes, des canapés, des téléviseurs, etc. Le type de téléviseur pourrait être le seul que nous ayons à avoir une consommation électrique. Je mettrais donc le power_consumption attribut sur le tv_type_table. Mais alors nous commençons à porter des systèmes de cinéma maison qui ont aussi un power_consumption propriété. OK c'est juste un autre produit alors je vais ajouter ce champ à la stereo_type_table aussi, puisque c'est probablement le plus facile à ce stade. Mais avec le temps, comme nous commençons à transporter de plus en plus d’électronique, nous réalisons que power_consumption est assez large pour qu'il soit dans le main_product_table. Qu'est-ce que je devrais faire maintenant?

Ajouter le champ à la main_product_table. Ecrivez un script pour parcourir l’électronique et mettez la valeur correcte de chaque type_table au main_product_table. Puis déposez cette colonne de chaque type_table.

Maintenant si j'utilisais toujours le même GetProductData classe d'interagir avec la base de données pour extraire les informations sur le produit; alors, si des modifications du code doivent maintenant être refactorisées, elles ne doivent concerner que cette classe.


5
2017-09-16 19:31



Vous pouvez avoir une table Product et une table ProductAdditionInfo séparée avec 3 colonnes: ID du produit, nom de l'info supplémentaire, valeur d'information supplémentaire. Si la couleur est utilisée par de nombreux produits, mais pas tous, vous pouvez la définir comme colonne nullable dans la table Product ou simplement la placer dans ProductAdditionalInfo.

Cette approche n'est pas une technique traditionnelle pour une base de données relationnelle, mais je l'ai vu beaucoup utilisée dans la pratique. Il peut être flexible et performant.

Steve Yegge appelle cela le motif Propriétés et a écrit un long post sur son utilisation.


3
2018-03-30 01:44