Entidades aninhadas e cálculo na propriedade da entidade folha - abordagem SQL ou NoSQL


10

Estou trabalhando em um projeto de hobby chamado Gerenciamento de Menu / Receita.

É assim que minhas entidades e suas relações se parecem.

A Nutrienttem propriedades CodeeValue

Um Ingredienttem uma coleção deNutrients

A Recipetem uma coleção de Ingredientse ocasionalmente pode ter uma coleção de outrosrecipes

A Mealtem uma coleção de RecipeseIngredients

A Menutem uma coleção deMeals

As relações podem ser descritas como

Entidades e Relacionamentos do Menu

Em uma das páginas, para um menu selecionado, preciso exibir as informações de nutrientes efetivas calculadas com base em seus constituintes (refeições, receitas, ingredientes e os nutrientes correspondentes).

No momento, estou usando o SQL Server para armazenar os dados e estou navegando na cadeia a partir do meu código C #, começando em cada refeição do menu e agregando os valores dos nutrientes.

Acho que não é uma maneira eficiente, pois esse cálculo está sendo feito toda vez que a página é solicitada e os constituintes mudam ocasionalmente.

Eu estava pensando em ter um serviço em segundo plano que mantém uma tabela chamada MenuNutrients ( {MenuId, NutrientId, Value}) e preencherá / atualizará esta tabela com os nutrientes efetivos quando qualquer componente (Refeição, Receita, Ingrediente) for alterado.

Eu sinto que um GraphDB seria um bom ajuste para esse requisito, mas minha exposição ao NoSQL é limitada.

Quero saber quais são as soluções / abordagens alternativas para esse requisito de exibir os nutrientes de um determinado menu.

Espero que minha descrição do cenário seja clara.


Quantos objetos estamos falando? O desempenho será realmente um problema?
Flup

@flup Em média, um menu pode ter 8 refeições, cada refeição pode ter 2 receitas e 2 ingredientes, cada receita pode ter 6-8 ingredientes.
Chandu

Suas flechas não estão na direção errada?
Branko Dimitrijevic 10/10

Você já viu uma amostra do Nerd Dinner Entity Framework?
Akash Kava

Respostas:


8

Com base nos requisitos e na arquitetura, pode haver opções de melhoria de desempenho:

  • Você pode usar modos de exibição indexados (matrializados) Para melhorar o desempenho de leitura no nível RDBMS (servidor Sql).
    Basicamente, tudo que você precisa fazer é:
    Criar uma exibição regular.
    Crie um índice em cluster nessa exibição .

  • O uso de um mecanismo de desconto no nível do aplicativo melhorará o desempenho.
    Se for possível e viável usar o dinheiro, ter uma estratégia de caixa como o dinheiro simples e preguiçoso o ajudará.

NoSql:
Existem muitos bons artigos sobre Sql vs NoSql, como este e este.

As partes me interessam:

Onde usar o NoSql:

Se o seu banco de dados for 3NF e você não fizer nenhuma junção (você está apenas selecionando várias tabelas e juntando todos os objetos, também conhecido como o que a maioria das pessoas faz em um aplicativo da web.

Quando usado, esteja pronto para:

  • Você acaba escrevendo trabalhos para fazer coisas como juntar dados de diferentes tabelas / coleções, algo que um RDBMS faria automaticamente por você.
  • Seus recursos de consulta com o NoSQL são drasticamente prejudicados. O MongoDb pode ser a coisa mais próxima do SQL, mas ainda está muito atrás. Confie em mim. As consultas SQL são super intuitivas, flexíveis e poderosas. As consultas NoSql não são.
  • As consultas do MongoDb podem recuperar dados de apenas uma coleção e tirar proveito de apenas um índice. E o MongoDb é provavelmente um dos bancos de dados NoSQL mais flexíveis. Em muitos cenários, isso significa mais viagens de ida e volta ao servidor para encontrar registros relacionados. E então você começa a desnormalizar os dados - o que significa trabalhos em segundo plano.
  • O fato de não ser um banco de dados relacional significa que você não terá (acredita-se que alguns tenham mau desempenho) restrições de chave estrangeira para garantir que seus dados sejam consistentes. Garanto que isso acabará criando inconsistências de dados em seu banco de dados. Esteja preparado. Provavelmente, você começará a escrever processos ou verificações para manter seu banco de dados consistente, o que provavelmente não terá um desempenho melhor do que permitir que o RDBMS faça isso por você.
  • Esqueça estruturas maduras como o hibernate.

Ao lado de decidir usar ou não usar NoSQL, um artigo útil sobre NoSQL DBMS Comparação e a intenção deles poderia ser encontrado aqui , como alguns deles estão focados em alta lê, escreve baixos, Map-Reduce, HA ...
Ter um olhar no ranking e popularidade deles , por categoria pode ser útil.


Obrigado pelos detalhes. Irá verificar os links e voltar para você.
Chandu

3

Na verdade, você não precisa usar um gráfico db, apenas armazene os valores necessários em um nível superior. É como armazenar um Ordere OrderItems. você não precisa calcular o total toda vez que um pedido está prestes a ser exibido. Em vez disso, basta calcular a soma, o IVA e outras coisas e armazená-las com o seu Order.

order.Subtotal = order.Items.Sum(item => item.Price);
order.Tax = order.Subtotal * 0.25m; // just a value
order.Total = order.Subtotal + order.Tax;

// fast forward time
var subTotal = order.Items.Sum(item => item.Price);
var tax = subTotal * 0.25m;
var total = subTotal + tax;

if (toal == order.Total) {
   Console.Log("Why the hell I've just re-calculated total?");
}

3

Sugiro examinar o padrão de Segregação de Responsabilidade de Consulta de Comando .

Basicamente, em vez de criar um único modelo para ler e escrever, você pode criar 2 modelos diferentes. Um otimizado para atualização e o outro otimizado para consultas (leitura, relatórios, ...). Os 2 modelos são sincronizados (geralmente com consistência eventual) usando eventos de domínio (consulte DDD).

Comecei a estudar esse padrão há alguns meses e realmente mudou minha maneira de modelar software. Não é fácil porque é uma grande mudança, especialmente quando usado com outras técnicas como DDD e Event Sourcing. Mas vale a pena.

Existem muitos recursos disponíveis na rede, procure CQRS e DDD (e eventualmente Event Sourcing).

Esse padrão pode ser usado no SQL e noSql.

No seu caso, você pode disparar um evento toda vez que os nutrientes forem alterados para atualizar o modelo de leitura otimizado para leitura. O modelo de leitura pode ser, por exemplo, uma visualização desnormalizada dos nutrientes do menu (por que não usar um nosql db para uma leitura eficiente)? Você pode ter vários modelos de leitura com base nas consultas que você precisa executar.

Existem algumas implicações nessa abordagem, mas é muito escalável e extensível.


Essa era a abordagem que eu estava pensando, mas não tinha certeza de como obter os dados para o modelo de leitura (basicamente, algum processo deveria me fornecer os dados para o modelo de leitura).
Chandu

Geralmente, o modelo de leitura é atualizado a cada alteração. Você deve implementar a interface do usuário com comandos (com base em tarefas) em vez de usar operações crud. Dessa maneira, todos os comandos são refletidos no modelo de leitura. Você não precisa executar outras consultas. Os comandos de design permitem ao sistema capturar a real intenção do usuário.

2

Depende muito de como você faz para obter os menus e os nutrientes inicialmente. Por que você acha que não será eficiente?

Pelo que entendi, você vai ao banco de dados, pega o menu, depois vai de novo, pega cada receita, depois vai de novo, pega cada ingrediente e assim por diante. Isso é realmente ineficiente, pois há muitas consultas e viagens de ida e volta ao servidor, que é a principal fonte de atrasos. Isso é conhecido como o problema SELECT N + 1.

O que você deve fazer é buscar todos os dados em uma única consulta, usando JOINs para todas as tabelas do menu até os nutrientes, para que o servidor de banco de dados possa usar todos os relacionamentos e índices para obter os dados de uma só vez. O aplicativo C # do cliente processa apenas e exibe o resultado final. Fazer isso é muito mais eficiente do que ir um por um.

Em geral, usando técnicas de consulta adequadas e os índices certos para consultas críticas, os bancos de dados relacionais podem ter um desempenho muito bom em grandes tabelas sob carga.


Obrigado, entendo que depende das junções. Como os constituintes do menu mudam ocasionalmente, não quero executar o cálculo sempre que alguém acessa a página. Em vez disso, quero um serviço em segundo plano para fazer o cálculo e posso simplesmente lê-lo em uma tabela quando necessário. O problema com o cálculo é identificar toda a cadeia quando um dos constituintes é alterado.
Chandu

Apenas pesquisar alguns relacionamentos não implica em nenhum cálculo, mesmo que haja 5 ou 6 JOINs que não devam ser um fardo para o servidor (a menos que falemos em buscar centenas ou milhares de linhas), se a indexação adequada está no lugar. Mesmo com grandes conjuntos de dados, você sempre pode criar uma visualização de todo o resultado e até indexar a visualização para que o resultado seja pré-calculado, se o desempenho se tornar um problema.

2

Parece que você passou algum tempo pensando sobre a melhor forma de modelar os dados para que possam ser facilmente atualizados e consultados. No entanto, agora você está no ponto em que precisa fornecer acesso aos dados. Essas duas coisas são preocupações separadas.

Você mencionou que recarregar a página está causando uma nova consulta ao banco de dados. Você também mencionou que o banco de dados ocasionalmente será atualizado e quando você deseja que essas atualizações sejam exibidas na página em tempo hábil. Seu melhor método para reduzir a sobrecarga de consultas não é fazê-las. Se você estiver executando as mesmas consultas repetidamente e obtendo os mesmos resultados, por que não armazená-las em cache por um tempo? Você deve conseguir implementar algum cache upstream sem modificar o restante do projeto. Eu recomendaria ler sobre descanso. Independentemente de se você implementar o projeto em um rdbms ou nosql, é melhor lidar com problemas com o desempenho desse tipo, reduzindo o número de vezes que você precisa acessar o banco de dados. Digamos que você tenha 100 solicitações para a mesma receita em 60 segundos. Se você armazenar em cache por 60 segundos, você só acessará o banco de dados uma vez, o que representa uma melhoria de 100x no desempenho. Ver o mesmo nível de melhoria ao mudar para o nosql exigirá muito mais trabalho.

Os sistemas do tipo Nosql podem ser uma ótima solução quando você tem grandes quantidades de dados ou requisitos extremos de velocidade de leitura ou gravação. No entanto, esse desempenho extra tem um custo de desperdiçar coisas como integridade referencial.


1

Parece que, para a experiência ou para fins de conhecimento, você deseja experimentar o Graph-DB, mas seu exemplo é claramente um exemplo de dados hierárquicos nos quais podemos fazer drill down / up através de um nó. Não sou especialista em Graph / Neo DB, mas vejo que não há muita complexidade na maneira como o usuário / você pode solicitar dados desse esquema. Vejo que a escolha do design do banco de dados / esquema depende muito de como e que tipo de dados serão consultados. Como você usa o SQLSERVER "HierarchyI" D é a melhor opção do meu ponto de vista para colocar esses nós como parte da Árvore.


1

Minha sugestão é pensar como uma máquina e não como um humano. Pode parecer repetitivo, mas é no que as máquinas são boas. Uma coisa que você precisa se perguntar é "eu preciso recuperar todos os objetos para exibir na minha página?" Se sim, continue o que você está fazendo, comparado à recuperação de dados, os ciclos da CPU são desprezíveis ao fazer contas simples.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.