Contexte
Je suis en train de prototyper une conversion de notre base de données SGBDR vers MongoDB. Tout en dénormalisant, il semble que j'ai deux choix, l'un qui mène à plusieurs (millions) de petits documents ou l'autre à moins (des centaines de milliers) de gros documents.
Si je pouvais le distiller jusqu'à un simple analogue, ce serait la différence entre une collection avec moins de documents client comme ceci (en Java):
class Client { private String name; private Address address; // chaque CreditCard a des centaines d'instances de paiement private Set <CreditCard> cartes de crédit; }
ou une collection avec de nombreux documents de paiement comme celui-ci:
classe Paiement { privé Client client; privé CreditCard creditCard; privé Date payDate; privé float payAmount; }
Question
MongoDB est-il conçu pour préférer beaucoup, beaucoup de 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.-à-d. combien de cartes de crédit le client X possède-t-il? Quel était 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 pourraient m'aider à répondre à ma question.
Vous devrez certainement optimiser pour les requêtes que vous faites.
Voici ma meilleure estimation basée sur votre description.
Vous voudrez probablement connaître toutes les cartes de crédit pour chaque client, alors conservez un tableau de celles-ci dans l'objet client. Vous souhaiterez également probablement 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 ID et index. Vous souhaiterez probablement également ajouter un index sur la référence client.
Cela vous permettra de rechercher rapidement les paiements par client sans stocker à chaque fois l'intégralité de l'objet client.
Si vous souhaitez répondre à des questions telles que "Quel était le montant moyen payé par tous les clients le mois dernier", vous allez plutôt vouloir une carte/réduire pour tout ensemble de données important. Vous n'obtenez 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 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 les entrées indexées très rapidement. MongoDB est très bon pour trouver une pe aiguilles dans une grande botte de foin. MongoDB est pas très bon pour trouver la plupart 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 mappage/réduction pour les cas d'utilisation les plus rares.
Selon la propre documentation de MongoDB, il semble qu'il soit 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. Dans la pratique, la plupart des documents ne dépassent pas quelques kilo-octets. Considérez les documents plus comme des lignes dans un tableau que les tableaux eux-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 générales pour la conception de schémas MongoDB: Partie 1 :
Modélisation un à peu
Un exemple de "one-to-few" pourrait être les adresses d'une personne. Il s'agit d'un bon cas d'utilisation pour l'incorporation - vous devez placer les adresses dans un tableau à l'intérieur de votre objet Personne.
Un-à-plusieurs
Un exemple de "un à plusieurs" peut être les pièces d'un produit dans un 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 quelques milliers. Il s'agit d'un bon cas d'utilisation pour le référencement - vous devez placer les ObjectID des pièces dans un tableau dans le document produit.
One-to-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é peut générer suffisamment de messages pour dépasser la taille du document de 16 Mo, même si tout ce que vous avez stocké dans le tableau était l'ObjectID. Il s'agit du cas d'utilisation classique pour le "référencement parent" - vous auriez un document pour l'hôte, puis stockez l'ObjectID de l'hôte dans les documents pour les messages de journal.
Les documents qui augmentent considérablement avec le temps peuvent être des bombes à retardement. La bande passante du réseau et l'utilisation de 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. Voyons si les documents client contiennent des tableaux d'informations de compte ou si vous avez besoin d'une nouvelle collection de comptes.
Si les documents de compte sont distincts 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 peut se traduire par une mémoire supplémentaire, des E/S, une 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érenceriez-vous? Les documents de compte distincts 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 réellement contenir tous les paiements effectués dans un délai fixe (par exemple, le jour?). Cette 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, le crédit par exemple, pourrait faire référence à un paiement. Mais créeriez-vous une collection de crédits ou intégreriez-vous des informations de crédit dans les informations de paiement? Que se passerait-il si vous deviez ultérieurement 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 m'inquiète pas de voir des documents de plus en plus volumineux détruire ma candidature. 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'adorerais entendre vos découvertes. Bonne chance!