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

88

Contexte
Je prototypage une conversion de notre base de données SGBDR vers MongoDB. Lors de la dénormalisation, il me semble que j'ai deux choix, l'un qui mène à plusieurs (millions) de petits documents ou l'autre qui conduit à moins (des centaines de milliers) de gros documents.

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

Client de classe {
    nom de chaîne privé;
    adresse d'adresse privée;
    // chaque carte de crédit a des centaines d'instances de paiement
    private Set <CreditCard> creditCards;
}

ou une collection avec de très nombreux documents de paiement comme celui-ci:

Paiement de classe {
    client privé;
    carte de crédit privée;
    privé Date payDate;
    flottant privé 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? (c'est-à-dire combien de cartes de crédit le client X possède-t-il? vs quel a été le montant moyen payé par tous les clients le mois dernier?)

J'ai beaucoup regardé autour de moi, mais je ne suis tombé sur aucune des meilleures pratiques de schéma MongoDB qui m'aiderait à répondre à ma question.

André
la source

Réponses:

82

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

Voici ma meilleure estimation basée sur votre description.

Vous voudrez probablement connaître toutes les cartes de crédit de chaque client, alors gardez un tableau de celles-ci dans l'objet client. Vous voudrez probablement également avoir une référence client pour chaque paiement. Cela gardera le document de paiement relativement petit.

L'objet de paiement aura automatiquement son propre identifiant et index. Vous voudrez probablement également ajouter un index sur la référence client.

Cela vous permettra de rechercher rapidement des paiements par client sans stocker à chaque fois l'intégralité de l'objet client.

Si vous souhaitez répondre à des questions telles que "Quel a été le montant moyen payé par tous les clients le mois dernier?", Vous souhaiterez plutôt une carte / une réduction pour tout ensemble de données important. Vous n'obtenez pas cette réponse "en temps réel". Vous constaterez que stocker une «référence» au client est probablement suffisant pour ces réductions de carte.

Donc, pour répondre directement à votre question: MongoDB est-il conçu pour préférer beaucoup, beaucoup de 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 quelques aiguilles dans une grande botte de foin. MongoDB n'est pas très bon pour trouver la plupart des aiguilles dans la botte de foin. Créez donc vos données autour de vos cas d'utilisation les plus courants et écrivez des tâches de mappage / réduction pour les cas d'utilisation les plus rares.

Vice-président Gates
la source
30

Selon la documentation de MongoDB, il semble qu'il soit conçu pour de nombreux petits documents.

À partir des 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 plus comme des lignes dans un tableau que les tableaux eux-mêmes. Plutôt que de conserver des listes d'enregistrements dans un seul document, faites plutôt de chaque enregistrement un document.

À partir de 6 règles de base pour la conception de schémas MongoDB: Partie 1 :

Modélisation One-to-Few

Un exemple de «un-à-quelques-uns» pourrait être les adresses d'une personne. C'est un bon cas d'utilisation pour l'incorporation - vous placeriez les adresses dans un tableau à l'intérieur de votre objet Person.

Un-à-plusieurs

Un exemple de «un-à-plusieurs» pourrait être les pièces d'un produit dans un système de commande de pièces de rechange. Chaque produit peut contenir jusqu'à plusieurs centaines de pièces de rechange, mais jamais plus de quelques milliers. C'est un bon cas d'utilisation pour le référencement - vous placeriez les ObjectID des pièces dans un tableau dans le document produit.

Un à Squillions

Un exemple de «one-to-squillions» pourrait être un système de journalisation des événements qui collecte des messages de journal pour différentes machines. Tout hôte donné pourrait générer suffisamment de messages pour dépasser la taille de document de 16 Mo, même si tout ce que vous avez stocké dans le tableau était l'ObjectID. C'est le cas d'utilisation classique du «référencement parent» - vous auriez un document pour l'hôte, puis vous stockeriez l'ObjectID de l'hôte dans les documents pour les messages du journal.

bmaupin
la source
11

Les documents qui grossissent considérablement avec le 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, vous obligeant à recommencer.

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

Ensuite, vous devez décider comment modéliser les informations de compte, telles que les cartes de crédit. Examinons si les documents client contiennent des tableaux d'informations sur les comptes ou si vous avez besoin d'une nouvelle collection de comptes.

Si les documents de compte sont séparés des documents client, le chargement de tous les comptes d'un client en mémoire nécessite la récupération de plusieurs documents. Cela pourrait se traduire par une mémoire supplémentaire, des E / S, de la bande passante et une utilisation du processeur. Cela signifie-t-il immédiatement que la collecte de comptes est une mauvaise idée?

Votre décision affecte les documents de paiement. Si les informations de compte sont intégrées dans un document client, comment les référeriez-vous? Les documents de compte séparés ont leur propre attribut _id. Avec les informations de compte intégrées, votre application générerait de nouveaux identifiants pour les comptes ou utiliserait les attributs du compte (par exemple, le numéro de compte) pour la clé.

Un document de paiement pourrait-il contenir tous les paiements effectués dans un délai fixe (par exemple, un jour?). Une telle complexité affectera tout le code qui lit et écrit les documents de paiement. L'optimisation prématurée peut être mortelle pour les 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, crédit par exemple, pourrait référencer un paiement. Mais voudriez-vous créer une collection de crédit ou intégreriez-vous des informations de crédit à l'intérieur des informations de paiement? Que se passerait-il si vous deviez plus tard référencer un crédit?

Pour résumer, j'ai réussi avec beaucoup de petits documents et de nombreuses collections. J'implémente des références avec _id et uniquement avec _id. Ainsi, je ne crains pas que des documents de plus en 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 se cachent pas dans d'autres documents.

J'aimerais connaître vos découvertes. Bonne chance!

Terris
la source