web-dev-qa-db-fra.com

Trop de duplication de données dans mongodb?

Je suis nouveau dans ce domaine NOSQL et j'ai récemment été intrigué par mongoDB. Je crée un nouveau site Web à partir de zéro et a décidé d’utiliser MONGODB/NORM (pour C #) comme seule base de données. J'ai beaucoup lu sur la façon de concevoir correctement votre base de données de modèles de documents et je pense que la plupart du temps, ma conception a été assez bien travaillée. Je suis sur mon nouveau site depuis environ 6 mois et je commence à voir des problèmes avec la duplication/synchronisation de données que je dois traiter encore et encore. D'après ce que j'ai lu, cela est attendu dans le modèle de document et, pour les performances, cela a du sens. C'EST À DIRE. vous collez des objets incorporés dans votre document pour une lecture rapide - pas de jointure; mais bien sûr, vous ne pouvez pas toujours intégrer, donc mongodb a ce concept de DbReference qui est fondamentalement analogue à une clé étrangère dans les bases de données relationnelles. 

Alors, voici un exemple: J'ai des utilisateurs et des événements; les deux obtiennent leur propre document, les utilisateurs assistent à des événements, les événements accueillent des utilisateurs. J'ai décidé d'intégrer une liste d'événements avec des données limitées dans les objets utilisateur. J'ai également intégré une liste d'utilisateurs dans les objets d'événement en tant que "participants". Le problème ici est maintenant que je dois garder les utilisateurs synchronisés avec la liste des utilisateurs qui est également incorporée dans l'objet Event. D'après ce que j'ai lu, cela semble être l'approche privilégiée et la méthode NOSQL pour faire les choses. La récupération est rapide, mais la solution de rechange est que lorsque je mets à jour le document Utilisateur principal, je dois également accéder aux objets Event, éventuellement rechercher toutes les références à cet utilisateur et les mettre à jour également.

Ma question est donc la suivante: s’agit-il d’un problème assez courant auquel les gens doivent s’attaquer? À quel point ce problème doit-il se produire avant de commencer à dire "peut-être que la stratégie NOSQL ne correspond pas à ce que j'essaie de faire ici"? À quel moment l'avantage en termes de performances de ne pas avoir à faire de jointes devient-il désavantageux parce que vous avez du mal à maintenir la synchronisation des données dans les objets incorporés et à effectuer plusieurs lectures dans la base de données pour le faire?

65
mike

C'est le compromis avec les magasins de documents. Vous pouvez stocker de manière normalisée, comme tout RDMS standard, et vous devriez vous efforcer d'obtenir la normalisation autant que possible. C’est uniquement là où les performances sont mauvaises que vous devriez rompre la normalisation et aplatir vos structures de données. Le compromis est efficacité de lecture vs coût de mise à jour. 

Mongo a des index vraiment efficaces qui peuvent faciliter la normalisation comme un RDMS traditionnel (la plupart des magasins de documents ne vous le donnent pas gratuitement, raison pour laquelle Mongo est davantage un hybride que un magasin de documents pur). En utilisant cela, vous pouvez créer une collection de relations entre les utilisateurs et les événements. Cela ressemble à une table de substitution dans un magasin de données tabulaire. Indexez les champs événement et utilisateur. Cela devrait être assez rapide et vous aider à mieux normaliser vos données. 

J'aime tracer l'efficacité de l'aplatissement d'une structure par rapport au maintien de la normalisation du temps qu'il faut pour mettre à jour des données d'enregistrements par rapport à la lecture de ce dont j'ai besoin dans une requête. Vous pouvez le faire en termes de grande notation O mais vous n’êtes pas obligé d’être aussi exigeant. Il suffit de noter sur papier quelques chiffres basés sur quelques cas d’utilisation avec différents modèles pour les données et d’avoir un bon pressentiment quant au volume de travail requis.

Essentiellement, ce que je fais, c'est d'abord essayer de prédire la probabilité du nombre de mises à jour qu'un disque aura par rapport à la fréquence de lecture. Ensuite, j'essaie de prédire le coût d'une mise à jour par rapport à une lecture lorsqu'elle est à la fois normalisée ou aplatie (ou peut-être en partie avec les deux que je peux concevoir ... de nombreuses options d'optimisation). Je peux ensuite juger des économies réalisées grâce à la stabilisation par rapport au coût de constitution des données à partir de sources normalisées. Une fois que j'ai tracé toutes les variables, si les économies réalisées en le maintenant à plat me permettent d'économiser beaucoup, je le garderai en l'état. 

Quelques astuces:

  • Si vous souhaitez que les recherches rapides soient rapides et atomiques (parfaitement à jour), vous voudrez peut-être une solution privilégiant l’aplatissement à la normalisation et le succès de la mise à jour. 
  • Si vous souhaitez une mise à jour rapide et un accès immédiat, privilégiez la normalisation. 
  • Si vous avez besoin de recherches rapides mais que vous n’avez pas besoin de données parfaitement à jour, envisagez de construire vos données normalisées dans des travaux par lots (éventuellement en utilisant mappage/réduction). 
  • Si vos requêtes doivent être rapides et que les mises à jour sont rares et ne nécessitent pas nécessairement que votre mise à jour soit immédiatement accessible, ou si un verrouillage au niveau de la transaction est nécessaire 100% du temps (pour garantir que votre mise à jour a été écrite sur le disque), pouvez envisager d’écrire vos mises à jour dans une file d’attente en les traitant en arrière-plan. (Dans ce modèle, vous devrez probablement traiter plus tard de la résolution des conflits et de la réconciliation).
  • Profil différents modèles. Construisez une couche d'abstraction de requête de données (comme un ORM en quelque sorte) dans votre code afin que vous puissiez refactoriser ultérieurement la structure de votre magasin de données. 

Il y a beaucoup d'autres idées que vous pouvez utiliser. Il y a beaucoup d'excellents blogs en ligne comme highscalabilty.org et qui vous permettent de comprendre le théorème de la PAC. 

Pensez également à une couche de mise en cache, telle que Redis ou memcache. Je vais mettre un de ces produits devant ma couche de données. Lorsque j'interroge Mongo (qui stocke tout ce qui est normalisé), j'utilise les données pour créer une représentation aplatie et la stocker dans le cache. Lors de la mise à jour des données, toutes les données du cache qui référencent ce que je mets à jour sont invalidées. (Bien que vous deviez prendre le temps nécessaire pour invalider les données et suivre les données dans le cache en cours de mise à jour en tenant compte de vos facteurs de mise à l'échelle). Quelqu'un a dit un jour "Les deux choses les plus difficiles en informatique consistent à nommer les choses et à invalider le cache."

J'espère que cela pourra aider!

56
Zac Bowling

Essayez d’ajouter une IList de type propriété UserEvent à votre objet User. Vous n'avez pas précisé la conception de votre modèle de domaine. Consultez le groupe NoRM http://groups.google.com/group/norm-mongodb/topics Pour des exemples.

0
Peter Bromberg