MongoDB Schema Design - Muitos documentos pequenos ou menos documentos grandes?

88

Histórico
Estou fazendo o protótipo de uma conversão de nosso banco de dados RDBMS para MongoDB. Ao desnormalizar, parece que tenho duas opções, uma que leva a muitos (milhões) de documentos menores ou outra que leva a menos (centenas de milhares) de documentos grandes.

Se eu pudesse resumir em um simples análogo, seria a diferença entre uma coleção com menos documentos do cliente como este (em Java):

class Customer {
    nome da string privada;
    endereço de endereço privado;
    // cada cartão de crédito tem centenas de instâncias de pagamento
    Private Set <CreditCard> creditCards;
}

ou uma coleção com muitos, muitos documentos de pagamento como este:

class Payment {
    cliente particular do cliente;
    cartão de crédito privado;
    data privada payDate;
    float privado payAmount;
}

Pergunta
O MongoDB foi projetado para preferir muitos, muitos documentos pequenos ou menos documentos grandes? A resposta depende principalmente das consultas que pretendo executar? (ou seja, quantos cartões de crédito o cliente X possui? vs Qual foi o valor médio que todos os clientes pagaram no mês passado?)

Já procurei muito, mas não encontrei nenhuma das melhores práticas de esquema do MongoDB que pudesse me ajudar a responder à minha pergunta.

Andre
fonte

Respostas:

82

Definitivamente, você precisará otimizar para as consultas que está fazendo.

Aqui está meu melhor palpite com base em sua descrição.

Provavelmente, você desejará saber todos os Cartões de Crédito de cada Cliente, portanto, mantenha uma matriz deles no Objeto Cliente. Você provavelmente também desejará ter uma referência de cliente para cada pagamento. Isso manterá o documento de pagamento relativamente pequeno.

O objeto Pagamento terá automaticamente seu próprio ID e índice. Provavelmente, você também desejará adicionar um índice na referência do cliente.

Isso permitirá que você pesquise rapidamente os Pagamentos por cliente sem armazenar o objeto do cliente inteiro todas as vezes.

Se você quiser responder a perguntas como "Qual foi o valor médio que todos os clientes pagaram no mês passado", você vai querer um mapa / redução para qualquer conjunto de dados considerável. Você não está recebendo esta resposta "em tempo real". Você descobrirá que armazenar uma "referência" ao Cliente provavelmente é bom o suficiente para essas reduções de mapa.

Portanto, para responder diretamente à sua pergunta: O MongoDB foi projetado para dar preferência a muitos, muitos documentos pequenos ou menos documentos grandes?

O MongoDB foi projetado para localizar entradas indexadas muito rapidamente. O MongoDB é muito bom em encontrar algumas agulhas em um grande palheiro. O MongoDB não é muito bom em encontrar a maioria das agulhas no palheiro. Portanto, crie seus dados em torno dos casos de uso mais comuns e escreva mapear / reduzir trabalhos para os casos de uso mais raros.

Gates VP
fonte
30

De acordo com a própria documentação do MongoDB, parece que ele foi projetado para muitos documentos pequenos.

Das práticas recomendadas de desempenho para MongoDB :

O tamanho máximo para documentos no MongoDB é 16 MB. Na prática, a maioria dos documentos tem alguns kilobytes ou menos. Considere os documentos mais como linhas em uma tabela do que as próprias tabelas. Em vez de manter listas de registros em um único documento, transforme cada registro em um documento.

De 6 regras básicas para projeto de esquema do MongoDB: Parte 1 :

Modelagem de um para poucos

Um exemplo de “um para poucos” pode ser os endereços de uma pessoa. Este é um bom caso de uso para incorporação - você colocaria os endereços em um array dentro do seu objeto Person.

Um para muitos

Um exemplo de “um para muitos” pode ser peças para um produto em um sistema de pedido de peças de reposição. Cada produto pode ter até várias centenas de peças de reposição, mas nunca mais do que alguns milhares ou mais. Este é um bom caso de uso para referência - você colocaria os ObjectIDs das partes em um array no documento do produto.

Um para Squillions

Um exemplo de “um-para-squillions” pode ser um sistema de registro de eventos que coleta mensagens de registro para máquinas diferentes. Qualquer host pode gerar mensagens suficientes para estourar o tamanho do documento de 16 MB, mesmo se tudo o que você armazenou no array foi o ObjectID. Este é o caso de uso clássico para “referência de pai” - você teria um documento para o host e, em seguida, armazenaria o ObjectID do host nos documentos para as mensagens de log.

bmaupin
fonte
11

Documentos que crescem substancialmente com o tempo podem ser bombas-relógio. A largura de banda da rede e o uso de RAM provavelmente se tornarão gargalos mensuráveis, forçando você a começar de novo.

Primeiro, vamos considerar duas coleções: Cliente e Pagamento. Assim, o grão é bastante pequeno: um documento por pagamento.

Em seguida, você deve decidir como modelar as informações da conta, como cartões de crédito. Vamos considerar se os documentos do cliente contêm matrizes de informações de conta ou se você precisa de uma nova coleção de conta.

Se os documentos da conta forem separados dos documentos do cliente, carregar todas as contas de um cliente na memória requer a busca de vários documentos. Isso pode se traduzir em memória extra, E / S, largura de banda e uso de CPU. Isso significa imediatamente que a coleção de contas é uma má ideia?

Sua decisão afeta os documentos de pagamento. Se as informações da conta estiverem incorporadas a um documento do cliente, como você faria referência a elas? Documentos de conta separados têm seu próprio atributo _id. Com as informações de conta incorporadas, seu aplicativo geraria novos ids para contas ou usaria os atributos da conta (por exemplo, número da conta) para a chave.

Um documento de pagamento poderia realmente conter todos os pagamentos feitos em um prazo fixo (por exemplo, dia?). Essa complexidade afetará todo o código que lê e grava documentos de pagamento. A otimização prematura pode ser mortal para os projetos.

Como documentos de conta, pagamentos são facilmente referenciados, desde que um documento de pagamento contenha apenas um pagamento. Um novo tipo de documento, crédito, por exemplo, pode fazer referência a um pagamento. Mas você criaria uma Cobrança de crédito ou incorporaria informações de crédito às informações de pagamento? O que aconteceria se mais tarde você precisasse fazer referência a um crédito?

Para resumir, tenho tido sucesso com muitos documentos pequenos e muitas coleções. Implemento referências com _id e apenas com _id. Portanto, não me preocupo com o número cada vez maior de documentos destruindo meu aplicativo. O esquema é fácil de entender e indexar porque cada entidade tem sua própria coleção. Entidades importantes não estão escondidas em outros documentos.

Eu adoraria ouvir sobre suas descobertas. Boa sorte!

Terris
fonte