Entités imbriquées et calcul sur la propriété d'entité feuille - approche SQL ou NoSQL

10

Je travaille sur un projet de loisir appelé Gestion des menus / recettes.

Voilà à quoi ressemblent mes entités et leurs relations.

A Nutrienta des propriétés CodeetValue

An Ingredientpossède une collection deNutrients

A Recipepossède une collection de Ingredientset peut parfois avoir une collection d'autresrecipes

A Meala une collection de RecipesetIngredients

A Menupossède une collection deMeals

Les relations peuvent être décrites comme

Entités de menu et relations

Dans l'une des pages, pour un menu sélectionné, je dois afficher les informations sur les nutriments efficaces calculées en fonction de ses constituants (repas, recettes, ingrédients et nutriments correspondants).

À partir de maintenant, j'utilise SQL Server pour stocker les données et je navigue dans la chaîne à partir de mon code C #, en commençant à chaque repas du menu, puis en agrégeant les valeurs nutritives.

Je pense que ce n'est pas un moyen efficace car ce calcul est fait à chaque fois que la page est demandée et les constituants changent de temps en temps.

Je pensais à un service d'arrière-plan qui maintient une table appelée MenuNutrients ( {MenuId, NutrientId, Value}) et remplira / mettra à jour cette table avec les nutriments efficaces lorsque l'un des composants (repas, recette, ingrédient) change.

Je pense qu'un GraphDB serait bien adapté à cette exigence, mais mon exposition à NoSQL est limitée.

Je veux savoir quelles sont les solutions / approches alternatives à cette exigence d'affichage des nutriments d'un menu donné.

J'espère que ma description du scénario est claire.

Chandu
la source
De combien d'objets parlons-nous? La performance sera-t-elle vraiment un problème?
flup
@flup En moyenne, un menu peut avoir 8 repas, chaque repas peut avoir 2 recettes et 2 ingrédients, chaque recette peut avoir 6 à 8 ingrédients.
Chandu
Vos flèches ne vont-elles pas dans la mauvaise direction?
Branko Dimitrijevic du
Avez-vous vu un exemple de Nerd Dinner Entity Framework?
Akash Kava du

Réponses:

8

En fonction des exigences et de l'architecture, il peut y avoir des options d'amélioration des performances:

  • Vous pouvez utiliser des vues indexées (matrialisées) pour améliorer les performances de lecture au niveau du SGBDR (serveur SQL).
    Fondamentalement, tout ce que vous devez faire est de:
    Créer une vue régulière.
    Créez un index cluster sur cette vue .

  • L'utilisation d'un mécanisme d'encaissement au niveau de l'application améliorera les performances.
    S'il est possible et faisable d'utiliser l'encaissement, avoir une stratégie de trésorerie comme l' encaissement paresseux singleton vous aidera.

NoSql:
Il y a beaucoup de bons articles sur Sql vs NoSql, comme ceci et cela

Les parties m'intéressent:

Où utiliser NoSql:

Si votre base de données est 3NF et que vous ne faites aucune jointure (vous sélectionnez simplement un tas de tables et assemblez tous les objets, AKA ce que la plupart des gens font dans une application Web.

Lorsqu'il est utilisé, soyez prêt à:

  • Vous finissez par écrire des travaux pour faire des choses comme joindre des données de différentes tables / collections, quelque chose qu'un SGBDR ferait automatiquement pour vous.
  • Vos capacités de requête avec NoSQL sont considérablement paralysées. MongoDb est peut-être la chose la plus proche de SQL, mais elle est toujours extrêmement loin derrière. Croyez-moi. Les requêtes SQL sont super intuitives, flexibles et puissantes. Les requêtes NoSql ne le sont pas.
  • Les requêtes MongoDb peuvent récupérer des données à partir d'une seule collection et tirer parti d'un seul index. Et MongoDb est probablement l'une des bases de données NoSQL les plus flexibles. Dans de nombreux scénarios, cela signifie plus d'allers-retours vers le serveur pour rechercher les enregistrements associés. Et ensuite, vous commencez à dénormaliser les données - ce qui signifie des travaux en arrière-plan.
  • Le fait qu'il ne s'agisse pas d'une base de données relationnelle signifie que vous n'aurez pas de contraintes de clé étrangère (considérées par certains comme peu performantes) pour garantir la cohérence de vos données. Je vous assure que cela va éventuellement créer des incohérences de données dans votre base de données. Soyez prêt. Vous commencerez très probablement à écrire des processus ou des vérifications pour garder votre base de données cohérente, ce qui ne fonctionnera probablement pas mieux que de laisser le SGBDR le faire pour vous.
  • Oubliez les frameworks matures comme hibernate.

En plus de décider d'utiliser ou de ne pas utiliser NoSQL, un article utile sur Comparaison SGBD NoSQL et l'intention d'entre eux pourraient être trouvés ici que certains d'entre eux sont concentrés sur haut Reads bas écrit, la carte-Reduce, HA ...
Avoir un regard au classement et à leur popularité , par catégorie peut être utile.

Mohsen Heydari
la source
Merci pour les détails. Va vérifier les liens et vous recontacter.
Chandu
3

En fait, vous n'avez pas besoin d'utiliser un graphe db, stockez simplement les valeurs requises dans un niveau supérieur. C'est comme stocker un Orderet OrderItems. vous n'avez pas à calculer le total chaque fois qu'une commande est sur le point d'être affichée. Au lieu de cela, vous calculez simplement la somme, la TVA et d'autres choses et les stockez avec votre Order.

order.Subtotal = order.Items.Sum(item => item.Price);
order.Tax = order.Subtotal * 0.25m; // just a value
order.Total = order.Subtotal + order.Tax;

// fast forward time
var subTotal = order.Items.Sum(item => item.Price);
var tax = subTotal * 0.25m;
var total = subTotal + tax;

if (toal == order.Total) {
   Console.Log("Why the hell I've just re-calculated total?");
}

la source
3

Je suggère de regarder le modèle de séparation de la responsabilité des requêtes de commande .

Fondamentalement, au lieu de créer un seul modèle pour lire et écrire, vous pouvez créer 2 modèles différents. L'un optimisé pour la mise à jour et l'autre optimisé pour les requêtes (lecture, reporting, ...). Les 2 modèles sont synchronisés (généralement avec une cohérence éventuelle) à l'aide des événements de domaine (voir DDD).

J'ai commencé à étudier ce modèle il y a quelques mois et cela a vraiment changé ma façon de modéliser les logiciels. Ce n'est pas facile car c'est un grand changement, surtout lorsqu'il est utilisé avec d'autres techniques comme DDD et Event Sourcing. Mais ça vaut le coup.

Il existe de nombreuses ressources disponibles sur le net, recherchez CQRS et DDD (et éventuellement Event Sourcing).

Ce modèle peut être utilisé à la fois sur SQL et sur noSql.

Dans votre cas, vous pouvez déclencher un événement chaque fois que les nutriments sont modifiés pour mettre à jour le modèle de lecture optimisé pour la lecture. Le modèle de lecture peut être par exemple une vue dénormalisée des nutriments du menu (pourquoi ne pas utiliser une base de données nosql pour une lecture efficace). Vous pouvez avoir plusieurs modèles de lecture en fonction des requêtes que vous devez effectuer.

Il y a quelques implications en utilisant cette approche mais elle est très évolutive et extensible.

Davide Icardi
la source
C'était l'approche que j'envisageais, mais je ne savais pas comment obtenir les données pour le modèle de lecture (en gros, un processus devrait m'obtenir les données pour le modèle de lecture).
Chandu
Habituellement, le modèle lu est mis à jour à chaque changement. Vous devez implémenter l'interface utilisateur avec des commandes (basées sur les tâches) au lieu d'utiliser des opérations crud. De cette façon, chaque commande est répercutée sur le modèle de lecture. Vous n'avez pas besoin d'exécuter d'autres requêtes. Les commandes de conception permettent au système de capturer l'intention réelle de l'utilisateur.
2

Cela dépend grandement de la façon dont vous obtenez les menus et les nutriments au départ. Pourquoi pensez-vous que ce ne sera pas efficace?

D'après ce que je comprends, vous allez à la base de données, obtenez le menu, puis recommencez, récupérez chaque recette, puis recommencez et récupérez chaque ingrédient, etc. C'est vraiment inefficace, car il y a beaucoup de requêtes et d'aller-retour vers le serveur, qui est la principale source de retards. Ceci est connu comme le problème SELECT N + 1.

Ce que vous devez faire est de récupérer toutes les données dans une seule requête, en utilisant JOINs pour toutes les tables du menu jusqu'aux nutriments, afin que le serveur de base de données puisse utiliser toutes les relations et les index pour obtenir les données en une seule fois. L'application cliente C # traite et affiche uniquement le résultat final. Cela est beaucoup plus efficace que d'aller un par un.

En général, en utilisant les techniques de requête appropriées et les bons index pour les requêtes critiques, les bases de données relationnelles peuvent très bien fonctionner sur de grandes tables sous charge.


la source
Merci, je comprends que cela dépend des jointures. Étant donné que les composants du menu changent de temps en temps, je ne veux pas exécuter le calcul chaque fois que quelqu'un accède à la page. Au lieu de cela, je veux qu'un service d'arrière-plan fasse le calcul et je peux simplement le lire dans un tableau en cas de besoin. Le problème avec le calcul est d'identifier toute la chaîne lorsque l'un des constituants change.
Chandu
La simple recherche de quelques relations n'entraîne aucun calcul, même s'il y a 5 ou 6 JOINs qui ne devraient pas être une charge pour le serveur (sauf si nous parlons de récupérer des centaines ou des milliers de lignes), si l'indexation appropriée est en place. Même avec des ensembles de données volumineux, vous pouvez toujours créer une vue sur l'ensemble du résultat, et même indexer la vue pour que le résultat soit précalculé, si les performances deviennent un problème.
2

Il semble que vous ayez passé du temps à réfléchir à la meilleure façon de modéliser les données afin qu'elles puissent être facilement mises à jour et interrogées. Cependant, vous êtes maintenant au point où vous devez donner accès aux données. Ces deux choses sont des préoccupations distinctes.

Vous mentionnez que le rechargement de la page provoque une nouvelle requête dans la base de données. Vous mentionnez également que la base de données sera mise à jour de temps en temps et lorsque vous souhaitez que ces mises à jour soient affichées sur la page en temps opportun. Votre meilleure méthode pour réduire les frais généraux des requêtes est de ne pas les faire. Si vous exécutez les mêmes requêtes encore et encore et obtenez les mêmes résultats, pourquoi ne pas les mettre en cache pendant un certain temps? Vous devriez pouvoir implémenter une certaine mise en cache en amont sans modifier le reste du projet. Je recommanderais de lire sur le repos. Peu importe si vous implémentez le projet dans un rdbms ou nosql, les problèmes de performances de ce type sont mieux traités en réduisant le nombre de fois où vous devez vous rendre dans la base de données. Supposons que vous ayez 100 demandes pour la même recette en 60 secondes. Si vous mettez en cache pendant 60 secondes, vous n'appuyez sur la base de données qu'une seule fois, ce qui représente une amélioration de 100 fois les performances. Pour voir ce même niveau d'amélioration en passant à nosql, il faudra beaucoup plus de travail.

Les systèmes de type Nosql peuvent être une excellente solution lorsque vous avez d'énormes quantités de données ou des exigences de vitesse de lecture ou d'écriture extrêmes. Cependant, cette performance supplémentaire a un coût de rejet de choses comme l'intégrité référentielle.


la source
1

Il semble que dans le cadre de l'expérience ou de la connaissance, vous souhaitiez essayer Graph-DB, mais votre exemple est clairement un exemple de données hiérarchiques où nous pouvons effectuer une exploration / montée à travers un nœud. Je ne suis pas expert en Graph / Neo DB mais je peux voir qu'il n'y a pas beaucoup de complexité dans la façon dont l'utilisateur / vous pouvez demander des données à partir de ce schéma. Je vois que le choix de la conception de la base de données / du schéma dépend beaucoup de la manière et du type de données qui seront interrogés. Comme vous utilisez SQLSERVER "HierarchyI" D est la meilleure option de mon point de vue pour placer ces nœuds dans le cadre de l'arborescence.

Anup Shah
la source
1

Ma suggestion est de penser comme une machine et non comme un humain. Cela peut sembler répétitif, mais c'est à cela que les machines sont bonnes. Une chose que vous devez vous demander est "dois-je récupérer chaque objet, de toute façon, pour l'afficher sur ma page?" Si oui, continuez ce que vous faites, par rapport à la récupération de données, les cycles de processeur sont négligeables lorsque vous faites des calculs simples.

Robert Co
la source