MongoDB Schema Design - Molti piccoli documenti o meno documenti grandi?


89

Background
Sto prototipando una conversione dal nostro database RDBMS a MongoDB. Durante la denormalizzazione, sembra che io abbia due scelte, una che porta a molti (milioni) di documenti più piccoli o una che porta a meno (centinaia di migliaia) documenti di grandi dimensioni.

Se potessi distillarlo in un semplice analogo, sarebbe la differenza tra una raccolta con meno documenti cliente come questo (in Java):

classe Cliente {
    nome stringa privato;
    indirizzo di indirizzo privato;
    // ogni carta di credito ha centinaia di istanze di pagamento
    private Set <CreditCard> creditCards;
}

o una raccolta con molti, molti documenti di pagamento come questo:

class Payment {
    cliente cliente privato;
    CreditCard privato creditCard;
    data privata payDate;
    private float payAmount;
}

Domanda
MongoDB è progettato per preferire molti, molti piccoli documenti o meno documenti grandi? La risposta dipende principalmente dalle query che intendo eseguire? (ad esempio, quante carte di credito ha il cliente X? vs Qual è stato l'importo medio pagato da tutti i clienti il ​​mese scorso?)

Mi sono guardato intorno molto ma non sono incappato in nessuna best practice per lo schema MongoDB che mi aiutasse a rispondere alla mia domanda.

Risposte:


82

Avrai sicuramente bisogno di ottimizzare per le query che stai facendo.

Ecco la mia ipotesi migliore basata sulla tua descrizione.

Probabilmente vorrai conoscere tutte le carte di credito per ogni cliente, quindi tieni una serie di quelle all'interno dell'oggetto cliente. Probabilmente vorrai anche avere un riferimento cliente per ogni pagamento. Ciò manterrà il documento di pagamento relativamente piccolo.

L'oggetto Payment avrà automaticamente il proprio ID e indice. Probabilmente vorrai aggiungere un indice anche al riferimento del cliente.

Ciò ti consentirà di cercare rapidamente i pagamenti per cliente senza memorizzare ogni volta l'intero oggetto cliente.

Se desideri rispondere a domande come "Qual è stato l'importo medio pagato da tutti i clienti il ​​mese scorso", vorrai invece una mappa / riduzione per qualsiasi set di dati di dimensioni considerevoli. Non ricevi questa risposta "in tempo reale". Scoprirai che la memorizzazione di un "riferimento" al cliente è probabilmente sufficiente per queste riduzioni di mappa.

Quindi, per rispondere direttamente alla tua domanda: MongoDB è progettato per preferire molti, molti piccoli documenti o meno documenti grandi?

MongoDB è progettato per trovare le voci indicizzate molto rapidamente. MongoDB è molto bravo a trovare alcuni aghi in un grande pagliaio. MongoDB non è molto bravo a trovare la maggior parte degli aghi nel pagliaio. Quindi crea i tuoi dati intorno ai tuoi casi d'uso più comuni e scrivi mappare / ridurre i lavori per i casi d'uso più rari.


32

Secondo la documentazione di MongoDB, sembra che sia progettato per molti piccoli documenti.

Dalle migliori pratiche sulle prestazioni per MongoDB :

La dimensione massima per i documenti in MongoDB è di 16 MB. In pratica la maggior parte dei documenti sono pochi kilobyte o meno. Considera i documenti più simili alle righe di una tabella che alle tabelle stesse. Piuttosto che mantenere elenchi di record in un unico documento, trasforma ogni record in un documento.

Da 6 regole pratiche per MongoDB Schema Design: Parte 1 :

Modellazione da uno a pochi

Un esempio di "uno a pochi" potrebbe essere l'indirizzo di una persona. Questo è un buon caso d'uso per l'incorporamento: inseriresti gli indirizzi in un array all'interno del tuo oggetto Person.

Uno a molti

Un esempio di "uno a molti" potrebbe essere parti di un prodotto in un sistema di ordinazione di parti di ricambio. Ogni prodotto può contenere fino a diverse centinaia di parti di ricambio, ma mai più di un paio di migliaia. Questo è un buon caso d'uso per il riferimento: inseriresti gli ObjectID delle parti in un array nel documento del prodotto.

Uno a squillioni

Un esempio di "uno a squillioni" potrebbe essere un sistema di registrazione degli eventi che raccoglie i messaggi di registro per macchine diverse. Qualsiasi host dato potrebbe generare abbastanza messaggi da superare la dimensione del documento di 16 MB, anche se tutto ciò che hai memorizzato nell'array era l'ObjectID. Questo è il classico caso d'uso per "riferimento genitore": avresti un documento per l'host e quindi memorizzerai l'ObjectID dell'host nei documenti per i messaggi di registro.


13

I documenti che crescono sostanzialmente nel tempo possono essere bombe a orologeria. La larghezza di banda della rete e l'utilizzo della RAM diventeranno probabilmente colli di bottiglia misurabili, costringendoti a ricominciare da capo.

Innanzitutto, consideriamo due raccolte: Cliente e Pagamento. Quindi, il grano è abbastanza piccolo: un documento per pagamento.

Successivamente è necessario decidere come modellare le informazioni sull'account, come le carte di credito. Consideriamo se i documenti del cliente contengono matrici di informazioni sull'account o se è necessaria una nuova raccolta di account.

Se i documenti dell'account sono separati dai documenti del cliente, il caricamento di tutti gli account per un cliente in memoria richiede il recupero di più documenti. Ciò potrebbe tradursi in memoria aggiuntiva, I / O, larghezza di banda e utilizzo della CPU. Ciò significa immediatamente che la raccolta di account è una cattiva idea?

La tua decisione influisce sui documenti di pagamento. Se le informazioni sull'account sono incorporate in un documento del cliente, come le faresti riferimento? I documenti di account separati hanno il proprio attributo _id. Con le informazioni sull'account incorporate, l'applicazione genera nuovi ID per gli account o utilizza gli attributi dell'account (ad esempio, il numero di account) per la chiave.

Un documento di pagamento potrebbe effettivamente contenere tutti i pagamenti effettuati in un arco di tempo fisso (ad es. Giorno?). Tale complessità influenzerà tutto il codice che legge e scrive documenti di pagamento. L'ottimizzazione prematura può essere mortale per i progetti.

Come i documenti del conto, i pagamenti sono facilmente referenziati a condizione che un documento di pagamento contenga un solo pagamento. Un nuovo tipo di documento, ad esempio credito, potrebbe fare riferimento a un pagamento. Ma creereste una raccolta crediti o incorporereste le informazioni sul credito all'interno delle informazioni di pagamento? Cosa succederebbe se in seguito dovessi fare riferimento a un credito?

Per riassumere, ho avuto successo con molti piccoli documenti e molte raccolte. Implemento riferimenti con _id e solo con _id. Pertanto, non mi preoccupo che i documenti in continua crescita distruggano la mia applicazione. Lo schema è facile da capire e indicizzare perché ogni entità ha la propria raccolta. Entità importanti non si nascondono all'interno di altri documenti.

Mi piacerebbe conoscere le tue scoperte. In bocca al lupo!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.