Tableau des commandes de commerce électronique. Économisez des prix ou utilisez un tableau d'audit / historique?


13

Je conçois mon premier schéma de commerce électronique. Je lis sur le sujet depuis un petit moment et je suis un peu confus quant à la relation entre un order_line_itemet unproduct

Un productpeut être acheté. Il contient divers détails, mais le plus important est unit_price.

An order_line_itempossède une clé étrangère pour l' product_idachat, l' quantityachat et unit_pricele moment où le client a acheté le produit.

La plupart de ce que j'ai lu dit que le unit_pricesur le order_line_itemdevrait être explicitement ajouté (c'est-à-dire non référencé par le product_id). Cela a du sens, car le magasin pourrait changer le prix à l'avenir, ce qui gâcherait les rapports de commande, le suivi, l'intégrité, etc.

La chose que je ne comprends pas, c'est pourquoi enregistrer directement la unit_pricevaleur dans le order_line_item?

Ne serait-il pas préférable de créer un tableau d'audit / historique qui documente le unit_pricechangement d'un product?

Lorsqu'un order_line_itemest créé, la clé étrangère de la product_audittable est ajoutée et le prix peut être récupéré (par référence) à partir de là.

Il me semble qu'il y a beaucoup de points positifs à utiliser cette approche (moins de duplication des données, historique des changements de prix, etc.), alors pourquoi n'est-elle pas plus fréquemment utilisée? Je n'ai pas rencontré d'exemple de schéma de commerce électronique utilisant cette approche, ai-je raté quelque chose?

UDPATE: Il semble que ma question concerne la dimension à évolution lente . Je suis toujours confus, car la dimension à évolution lente concerne l'entrepôt de données et les OLAP. Les types de dimension à évolution lente peuvent-ils donc être appliqués à ma base de données de processus de transaction commerciale principale (OLTP)? Je me demande si je mélange beaucoup de concepts, j'apprécierais grandement quelques conseils.


En fait, je ferais les deux: stocker le prix de vente dans la ligne de commande et stocker un historique des prix des produits. Parce que les deux ont des objectifs différents. Le stockage du prix de vente rendra les requêtes sur les commandes beaucoup plus faciles et plus rapides. D'un autre côté, vous souhaiterez peut-être récupérer les anciens prix même pour les produits qui n'ont pas été vendus.
a_horse_with_no_name

Sûrement, rendre les requêtes de commandes plus faciles ne peut pas être le seul moteur derrière la sauvegarde du prix final à chaque fois. C'est une base de données relationnelle après tout - les requêtes ne seraient pas beaucoup plus difficiles.
Gaz_Edge

3
Le stockage du prix de vente dans la ligne de commande n'est pas "non relationnel" (et je considère qu'il est normalisé ainsi que le prix de vente est un attribut direct de la ligne de commande à mon avis). L'art d'utiliser une base de données relationnelle consiste à connaître les limites. Si vous exploitez une boutique avec 100 produits et 5 commandes par jour, le stockage et la récupération des anciens prix ne sont pas un problème. Si vous gérez un marché avec des millions de produits, des milliers de revendeurs et des centaines de commandes par minute, alors interroger cet historique sera un problème.
a_horse_with_no_name

Où stockeriez-vous les prix historiques? D'après ce que je lis, j'aurais besoin de deux bases de données. Un pour OLTP, un pour OLAP. L'histoire va dans l'OLAP?
Gaz_Edge

Réponses:


10

Comme vous l'avez identifié, le stockage du prix sur la commande facilite la mise en œuvre technique. Il existe un certain nombre de raisons commerciales pour lesquelles cela peut être bénéfique.

En plus des transactions Web, de nombreuses entreprises soutiennent les ventes via d'autres canaux, par exemple:

  • Par téléphone
  • Agents commerciaux "sur la route"
  • À un emplacement physique (p. Ex. Magasin, bureau)

Dans ces cas, la commande peut être entrée dans le système à un moment donné après la transaction. Dans ces circonstances, il peut être difficile, voire impossible, d'identifier correctement le relevé de prix historique à utiliser - le stockage du prix unitaire directement sur la commande est la seule option possible.

Plusieurs canaux posent souvent un autre défi - des prix différents pour le même produit. Les suppléments pour les commandes téléphoniques sont courants - et certains clients peuvent négocier eux-mêmes une remise. Vous pouvez être en mesure de représenter tous les prix possibles pour tous les canaux dans votre schéma de produit, mais l'incorporer dans vos tableaux de commande peut devenir (très) complexe.

Partout où cette négociation est autorisée, il devient très difficile de lier l'historique des prix au prix de la commande convenu (sauf si les agents ont des limites de négociation très étroites). Vous devez enregistrer le prix sur la commande elle-même.

Même si vous ne prenez en charge que les transactions Web et que vous avez une structure de prix relativement simple, il reste un problème intéressant à résoudre - comment gérer les augmentations de prix pour les transactions en vol? L'entreprise insiste-t-elle pour que le client paie des augmentations ou respecte-t-il le prix d'origine (lorsque le produit a été ajouté au panier)? Si c'est ce dernier, l'implémentation technique est compliquée - vous devez trouver un moyen de vous assurer que vous maintenez correctement la version des prix dans la session.

Enfin, de nombreuses entreprises commencent à utiliser une tarification très dynamique. Il peut ne pas y avoir un prix fixe pour un produit donné - il est toujours calculé au moment de l'exécution en fonction de facteurs tels que l'heure de la journée, la demande pour le produit, etc. Dans ces cas, le prix ne peut pas être stocké contre le produit en premier lieu!


3

J'ajouterai quelques points pratiques que j'ai vus.

  1. Les produits sont transitoires.

    Ce qu'ils peuvent signifier aujourd'hui peut ne pas être le même que ce qu'ils signifiaient il y a un an. Le même code sku (et donc le product_id) peut faire référence à différentes variantes / types de produits à différentes étapes.

    Tout le monde ne comprend pas toutes les préoccupations; par conséquent, un utilisateur peut modifier les attributs du produit d'origine au lieu d'en créer un nouveau à partir de sa propre ignorance. Souvent, cela peut se produire en raison du plan d'un utilisateur (Hé! Je ne peux avoir que 100 sku, alors pourquoi ne pas continuer à changer les plus anciens au lieu de mettre à jour le plan) Donc, vous voyez, dans beaucoup de chariots , un produit ne signifiera jamais la même chose pour toujours.

  2. Différents prix en fonction des conditions de commande et d'expédition

    Comme l'utilisateur @Chris l'a mentionné, différents prix peuvent être applicables dans différents scénarios.

    Dans la plupart des chariots, vous trouverez au moins 3 champs différents stockés - le prix unitaire, le montant de la remise et le prix réduit. Dans les plus avancés, vous en trouverez 2 de plus - prix unitaire avec taxe, prix réduit avec taxe. Vous pouvez trouver quelques champs supplémentaires pour décrire les frais de méthode d'expédition et les frais de méthode de paiement supplémentaires. Les pourcentages de taxe peuvent varier en fonction de l'État, du produit, du pays, de la méthode d'expédition, etc., tout comme les autres coûts. De même, les remises peuvent varier en fonction de la géographie, des promotions, du moment de la vente, etc. Par conséquent, il existe des informations qui peuvent être obtenues uniquement au niveau de la commande, et ces informations combinées ne peuvent pas être générées uniquement à partir des données du tableau des produits.

  3. Séparation des préoccupations

    Un grand nombre de charrettes sont implémentées de manière à ce que différentes équipes puissent avoir le contrôle sur différentes parties des données. Quelqu'un qui gère le système de commande n'a pas toujours besoin de savoir quels sont tous les produits en stock, quels étaient les prix à différents moments, quelles sont les alternatives pour une référence donnée, etc. La conservation des données relatives au produit avec les données de la commande permet de séparer les préoccupations. Cela pourrait également être vrai aux stades de développement, si différentes équipes gèrent différentes parties du système.

  4. Évolutivité facilitée sur plusieurs systèmes

    La plupart du temps, le système de gestion des commandes, le moteur de règles, le moteur de catalogue et le système de gestion de contenu sont tous construits / maintenus comme des systèmes distincts. Cela permet d'optimiser pour diverses conditions de charge et de générer une intelligence spécialisée pour chacun des systèmes. Un système ne peut donc pas être tenu pour rançon en raison de l'indisponibilité des informations d'un autre système.

  5. Développement et temps d'exécution plus rapides

    J'ai utilisé le terme «temps de développement» ici, bien que l'utilisation de «temps de débogage» serait plus appropriée. Chaque fois qu'un nouveau développement se produit, il sera plus rapide si les données nécessaires sont disponibles sans ajouter de complexité propre, car alors, il y aura des cycles de débogage comparativement plus petits.

    Imaginez que l'on vous demande de générer des rapports à la demande pour les remises offertes au jour le jour pour un mois donné il y a six mois. Si vous avez le prix d'origine, le prix réduit dans 1-2 tableaux avec la commande, les détails de l'article, c'est assez simple. Si toutefois, vous devez aller chercher les prix dans une autre table, puis les remises applicables dans une autre table, puis comprendre les détails, le développement et le temps d'exécution seront plus élevés.

Un bon design doit essayer d'optimiser autant pour l'avenir que pour le présent.


2

Cela peut finir par coûter plus cher en stockage, mais je préfère héberger tous les détails pertinents de la vente avec la transaction elle-même, de sorte que si, pour une raison quelconque, notre piste d'audit est rompue, ou si un administrateur remplace les sécurités en place, les détails de la vente comme: devise utilisée, prix unitaire, quantité, taxes appliquées et valeur, etc. sont disponibles. Je stocke généralement cela en XML afin qu'il puisse être flexible de vente en vente.


EDIT: Pour développer ce que je disais brièvement ci-dessus, dans mon commentaire de suivi ci-dessous, et ce que @a_horse_with_no_name a évoqué ci-dessus, la redondance dans les données de transaction est non seulement importante, mais elle est également nécessaire à grande échelle.

Je suppose que vous construisez en utilisant la POO et vous devriez donc probablement avoir un objet de transaction et soit un objet produit englobant tout le monde et / ou un objet prix. Dans ma propre expérience personnelle, je préfère être verbeux dans mon histoire, le stockage est relativement bon marché.

Ce que nous avons fait est de créer un historique des objets que vous pouvez faciliter en utilisant un SGBDR existant ou une sorte de magasin de valeurs clés NOSQL (ou encore mieux un SGBDR qui permet des connexions de type NoSQL comme handlersocket ou memcache), et nous stockons l'historique des objets de cette façon, avec chaque détail et changement de prix en un seul endroit facilement et rapidement disponibles. Si vous êtes sérieux, vous pouvez même utiliser les DIFF pour économiser sur le stockage et ne stocker que les modifications, bien qu'il ait ses propres mises en garde. Cela devrait prendre soin de votre historique, et l'avantage des objets sérialisés est que votre système pourra / devrait être capable de les récupérer comme les objets qu'ils ont été stockés. Cela prend soin de l'histoire.

En ce qui concerne ma suggestion, le stockage des détails de la transaction tels que les taxes, les devises, etc. avec la transaction elle-même signifie qu'il n'est pas nécessaire de chercher ailleurs pour ces détails, votre objet de transaction sera au courant de ses propriétés et vos vues peuvent se charger de présenter les données variables comme bon vous semble. Vous bénéficiez d'un accès rapide à l'instantané et bénéficiez en outre d'enregistrements redondants et vérifiables.

Ça vaut le coup, croyez-moi!


cela n'a pas vraiment de sens de dire que vous ne l'utilisez pas car il pourrait être supprimé. Vous pouvez remplacer toutes les données. Toute stratégie doit conserver les sauvegardes
Gaz_Edge

@Gaz_Edge Ils ne s'excluent pas mutuellement, vous pouvez toujours utiliser une piste d'audit et stocker les détails avec les transactions, la redondance dans ce cas est justifiée. Ne vous laissez jamais avec des données cet important sujet à un seul point de défaillance. Dans notre cas, j'utilise un magasin d'objets centralisé comme mécanisme d'historique plutôt que d'essayer de créer un historique par type d'objet (comme une transaction ou un produit dans ce cas). J'aurai à la fois l'intégralité de l'objet de transaction dans l'historique mais tous les détails les plus importants avec l'enregistrement lui-même. C'est entièrement à part les objets produits de l'histoire.
oucil

et si je voulais générer des rapports sur les commandes? Comme combien de produits x ont été achetés? Ou combien de commandes sur y montant? Enregistrer au format XML signifie que vous perdez la possibilité d'interroger les données, sauf erreur de
ma part

@Gaz_Edge Ce n'est pas vrai, si vous parlez de MySQL, vous en avez SELECT ExtractValue(field_name, '/x/path/');pour filtrer des choses comme, toutes les transactions dans une devise spécifique, ou toutes les transactions avec une certaine valeur fiscale minimale, ou autre. Des rapports à plus grande échelle peuvent être créés à partir de l'historique des objets. Pour les rapports à plus grande échelle, vous pouvez configurer un elasticsearchserveur / une instance qui a des rapports de style BigData et qui évolue facilement dans les millions de documents +.
oucil

@Gaz_Edge Je dois également mentionner que les rapports dont vous parlez (achats sur valeur, ventes de produits, etc.) sont des rapports courants et ceux-ci doivent avoir des valeurs stockées sous forme de valeurs en colonnes avec l'enregistrement de transaction pour un traitement plus rapide. Tout ce qui est important mais pas nécessairement signalé souvent peut entrer dans le XML. Les données instantanées ne sont vraiment que pour deux choses, 1. le problème de la dimension à évolution lente, et 2. la validation et la comparaison lorsqu'un client se plaint, et vous devez voir rapidement qui a raison. Ce n'est pas pour une utilisation quotidienne.
oucil

1

Mon vote serait de stocker le prix unitaire sur votre élément de campagne et de suivre l'historique des prix de vos produits dans un tableau séparé. Je justifie cela par une flexibilité accrue.

Même si votre structure de prix est rigide et bien définie et ne permet pas les variations mentionnées par @Chris Saxon ci-dessus, êtes-vous à l'aise que ce sera toujours le cas? Même si vous êtes confiant, pourquoi vous peindre dans un coin? Je pense que ce serait une bonne idée de le stocker sur le détail de l'élément de campagne, car je ne vois pas de raison impérieuse de le séparer.

Quant au stockage de votre historique de prix, il y a une valeur certaine à le stocker séparément car il pourrait y avoir des changements dans le prix d'un article et personne ne l'a acheté. Ce serait certainement une information utile pour savoir si un changement de prix était inefficace. Comme vous l'avez mentionné, il s'agit d'un cas d'utilisation classique d'une dimension à évolution lente de type 2 dans un scénario d'entrepôt de données. En règle générale, tout changement de prix dans votre tableau de produits est capturé et une nouvelle ligne est ajoutée au tableau de dimensions avec le prix mis à jour et un horodatage pour indiquer quand ce changement a eu lieu. La ligne précédente aurait sa date de fin mise à jour pour indiquer que ce n'est plus le prix effectif. Une approche consisterait donc à suivre ce type de changement dans un entrepôt de données.

Cependant, si vous ne voulez pas vous soucier de la conception d'un schéma d'entrepôt de données et d'un processus ETL en même temps que la conception de votre base de données de commerce électronique OLTP, cet historique pourrait certainement être capturé dans notre base de données de commerce électronique. Cela peut être fait comme vous l'avez décrit avec la création d'une table product_audit distincte qui se bloque de la table produit et contient les dates de début et de fin pour quand cette version d'un produit était en vigueur. Cela peut également être fait dans le tableau des produits lui-même en ajoutant des dates de début et de fin au tableau pour indiquer quel produit est actuellement actif. Cependant, en fonction du nombre de produits et du nombre ou des modifications de prix que votre entreprise subit, cela pourrait rendre votre tableau de produits beaucoup plus grand que prévu et pourrait entraîner des problèmes de performances des requêtes plus tard.

Enfin, séparer votre historique de prix du prix unitaire réel sur l'élément de campagne pourrait certainement donner d'autres opportunités analytiques pour voir quand un produit a été vendu à un prix supérieur ou inférieur au prix indiqué à l'époque.


Merci d'avoir répondu. Je pense que la stratégie que je vais adopter consistera à concevoir l'OLTP conformément au livre. En fait, j'aime l'idée d'avoir un entrepôt de données pour les rapports. Bien qu'il ajoute un travail supplémentaire (création d'un nouveau schéma), le schéma peut être adapté à OLAP. En quelque sorte, j'évite un scénario où j'essaye de placer une cheville carrée dans un trou rond.
Gaz_Edge

@Gaz_Edge: Suis dans une situation similaire en termes de prise de décision pour mon nouveau projet. Pouvez-vous s'il vous plaît partager vos réflexions sur l'approche de conception que vous avez adoptée il y a un an? Cela a-t-il bien fonctionné?
Coder Absolute

@CoderAbsolute ma solution d'origine était très orientée «base de données». Mon application est désormais centrée sur une architecture orientée services. J'ai maintenant de nombreux petits schémas de base de données découplés plutôt qu'un seul étroitement couplé. Le besoin de 3N sur un schéma massif est désormais révolu. Je viens donc d'ajouter le prix unitaire directement à la commande. Le maintien des variations historiques des prix des produits a maintenant disparu car il ne s'agissait pas d'une exigence commerciale. J'espère que cela pourra aider.
Gaz_Edge

0

Je suis totalement d'accord avec l'idée principale de garder ensemble les informations relatives à l'ordre (contexte). Juste une note secondaire mineure qu'une telle situation ne se produira que lorsque vous concevez votre application très centrée sur la base de données et que tout tourne autour de la grosse base de données. Si vous changez de point de vue en examinant le domaine problématique sous un angle différent, vous observerez clairement que l'ordre est un instantané capturé d'un événement très spécial dans le cycle de vie de votre application. Lorsque vous gérez des problèmes en fonction du contexte, les problèmes de base de données deviennent secondaires et la complexité que tout le monde craint d'interroger et de créer des rapports sera gérée de manière transparente dans le modèle de domaine.


Quelques petits exemples rendraient votre réponse beaucoup plus facile à comprendre. Surtout des phrases comme «l'ordre est un instantané capturé d'un événement très spécial dans le cycle de vie de votre application».
dezso
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.