78 votes

Conception de schémas MongoDB - Beaucoup de petits documents ou moins de gros documents ?

Contexte
Je suis en train de prototyper une conversion de notre base de données SGBDR vers MongoDB. Lors de la dénormalisation, j'ai l'impression d'avoir deux choix : celui qui conduit à de nombreux (millions) petits documents ou celui qui conduit à moins (centaines de milliers) de gros documents.

Si je pouvais le réduire à une simple analogie, ce serait la différence entre une collection avec moins de documents clients comme ceci (en Java) :

class Customer {
    private String name;
    private Address address;
    // each CreditCard has hundreds of Payment instances
    private Set<CreditCard> creditCards;
}

ou une collection avec beaucoup, beaucoup de documents de paiement comme celui-ci :

class Payment {
    private Customer customer;
    private CreditCard creditCard;
    private Date payDate;
    private float payAmount;
}

Question
MongoDB est-il conçu pour préférer de très nombreux petits documents ou moins de gros documents ? La réponse dépend-elle principalement des requêtes que je prévois d'exécuter ? (par exemple, combien de cartes de crédit le client X possède-t-il ? vs quel était le montant moyen payé par tous les clients le mois dernier) ?

J'ai beaucoup cherché, mais je ne suis pas tombé sur les meilleures pratiques en matière de schéma MongoDB qui m'auraient aidé à répondre à ma question.

78voto

Gates VP Points 26481

Vous devrez certainement optimiser les requêtes que vous effectuez.

Voici ce que je pense en me basant sur votre description.

Vous voudrez probablement connaître toutes les cartes de crédit de chaque client, et conserver un tableau de celles-ci dans l'objet Client. Vous voudrez probablement aussi avoir une référence client pour chaque paiement. Ainsi, le document de paiement sera relativement petit.

L'objet Paiement aura automatiquement son propre ID et son propre index. Vous voudrez probablement ajouter un index sur la référence du client également.

Cela vous permettra de rechercher rapidement les paiements par client sans avoir à stocker à chaque fois l'objet client complet.

Si vous voulez répondre à des questions comme "Quel a été le montant moyen payé par tous les clients le mois dernier ?" vous allez plutôt vouloir un map / reduce pour tout ensemble de données de taille importante. Vous n'obtiendrez pas cette réponse "en temps réel". Vous constaterez que le stockage d'une "référence" au client est probablement suffisant pour ces map-reduces.

Donc, pour répondre directement à votre question : MongoDB est-il conçu pour préférer de très nombreux petits documents ou moins de gros documents ?

MongoDB est conçu pour trouver très rapidement les entrées indexées. MongoDB est très efficace pour trouver une quelques des aiguilles dans une grande botte de foin. MongoDB est no très doué pour trouver le plus des aiguilles dans la botte de foin. Construisez donc vos données autour de vos cas d'utilisation les plus courants et écrivez des tâches de map/reduce pour les cas d'utilisation plus rares.

38voto

bmaupin Points 1428

D'après la documentation de MongoDB, il semble qu'il ait été conçu pour de nombreux petits documents.

De Meilleures pratiques de performance pour MongoDB :

La taille maximale des documents dans MongoDB est de 16 Mo. En pratique, la plupart des documents font quelques kilo-octets ou moins. Considérez les documents comme des lignes d'une table que les tables elles-mêmes. Plutôt que de maintenir des listes d'enregistrements dans un seul document, faites plutôt de chaque enregistrement un document.

De 6 règles d'or pour la conception de schémas MongoDB : 1ère partie :

Modélisation de l'un à l'autre

Un exemple de "un-à-peu" pourrait être les adresses d'une personne. Ce site est un bon cas d'utilisation pour l'intégration - vous mettez les adresses dans un tableau à l'intérieur de votre objet Personne.

Un à plusieurs

Un exemple de "one-to-many" peut être des pièces pour un produit dans une système de commande de pièces de rechange. Chaque produit peut avoir jusqu'à plusieurs centaines de pièces de rechange, mais jamais plus de deux mille ou plus. environ. Il s'agit d'un bon cas d'utilisation pour le référencement. les pièces dans un tableau dans le document du produit.

De un à plusieurs millions

Un exemple de "un à plusieurs" pourrait être un système d'enregistrement d'événements qui recueille des messages de journal pour différentes machines. Un hôte donné pourrait générer suffisamment de messages pour dépasser la taille du document de 16 Mo, même si tout ce que vous stockez dans le tableau est l'ObjectID. C'est le cas d'utilisation classique pour la "référence parentale" - vous auriez un document pour l'hôte, puis vous stockez l'ObjectID de l'hôte dans les documents pour les les messages du journal.

9voto

Terris Points 31

Les documents qui s'enrichissent considérablement au fil du temps peuvent être des bombes à retardement. La bande passante du réseau et l'utilisation de la RAM deviendront probablement des goulots d'étranglement mesurables, ce qui vous obligera à tout recommencer.

Tout d'abord, considérons deux collections : Client et Paiement. Le grain est donc assez petit : un document par paiement.

Ensuite, vous devez décider comment modéliser les informations relatives aux comptes, comme les cartes de crédit. Voyons si les documents clients contiennent des tableaux d'informations de compte ou si vous avez besoin d'une nouvelle collection Account.

Si les documents relatifs aux comptes sont distincts des documents relatifs aux clients, le chargement en mémoire de tous les comptes d'un client nécessite l'extraction de plusieurs documents. Cela peut se traduire par une utilisation supplémentaire de la mémoire, des E/S, de la bande passante et de l'unité centrale. Cela signifie-t-il immédiatement que la collecte des comptes est une mauvaise idée ?

Votre décision affecte les documents de paiement. Si des informations sur le compte sont intégrées dans un document client, comment les référencer ? Les documents de compte distincts ont leur propre attribut _id. Avec des informations de compte intégrées, votre application doit soit générer de nouveaux identifiants pour les comptes, soit utiliser les attributs du compte (par exemple, le numéro de compte) comme clé.

Un document de paiement peut-il réellement contenir tous les paiements effectués au cours d'une période donnée (par exemple, un jour) ? Une telle complexité affectera tout le code qui lit et écrit les documents de paiement. Une optimisation prématurée peut être fatale aux projets.

Comme les documents de compte, les paiements sont facilement référencés tant qu'un document de paiement ne contient qu'un seul paiement. Un nouveau type de document, le crédit par exemple, pourrait faire référence à un paiement. Mais créerait-on une collection de crédits ou intégrerait-on des informations de crédit dans des informations de paiement ? Que se passerait-il si vous deviez ultérieurement faire référence à un crédit ?

Pour résumer, j'ai réussi avec beaucoup de petits documents et de nombreuses collections. J'implémente les références avec _id et seulement avec _id. Ainsi, je n'ai pas à craindre que des documents toujours plus nombreux détruisent mon application. Le schéma est facile à comprendre et à indexer car chaque entité possède sa propre collection. Les entités importantes ne sont pas cachées dans d'autres documents.

J'aimerais connaître vos conclusions. Bonne chance !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X