Entidades anidadas y cálculo en la propiedad de la entidad hoja: enfoque SQL o NoSQL

10

Estoy trabajando en un proyecto de pasatiempo llamado Gestión de menús / recetas.

Así es como se ven mis entidades y sus relaciones.

A Nutrienttiene propiedades CodeyValue

An Ingredienttiene una colección deNutrients

A Recipetiene una Colección de Ingredientsy ocasionalmente puede tener una colección de otrosrecipes

A Mealtiene una colección de RecipesyIngredients

A Menutiene una colección deMeals

Las relaciones se pueden representar como

Entidades de menú y relaciones

En una de las páginas, para un menú seleccionado, necesito mostrar la información de nutrientes efectivos calculada en función de sus componentes (comidas, recetas, ingredientes y los nutrientes correspondientes).

A partir de ahora estoy usando SQL Server para almacenar los datos y estoy navegando por la cadena desde mi código C #, comenzando desde cada comida del menú y luego agregando los valores de nutrientes.

Creo que esta no es una forma eficiente, ya que este cálculo se realiza cada vez que se solicita la página y los componentes cambian ocasionalmente.

Estaba pensando en tener un servicio en segundo plano que mantenga una tabla llamada MenuNutrients ( {MenuId, NutrientId, Value}) y que llene / actualice esta tabla con los nutrientes efectivos cuando cambie cualquiera de los componentes (Comida, Receta, Ingrediente).

Siento que un GraphDB sería una buena opción para este requisito, pero mi exposición a NoSQL es limitada.

Quiero saber cuáles son las soluciones / enfoques alternativos para este requisito de mostrar los nutrientes de un menú determinado.

Espero que mi descripción del escenario sea clara.

Chandu
fuente
¿De cuántos objetos estamos hablando? ¿El rendimiento realmente será un problema?
flup
@flup En promedio, un menú puede tener 8 comidas, cada comida puede tener 2 recetas y 2 ingredientes, cada receta puede tener 6-8 ingredientes.
Chandu
¿No están tus flechas en la dirección equivocada?
Branko Dimitrijevic
¿Has visto el ejemplo de Nerd Dinner Entity Framework?
Akash Kava

Respuestas:

8

Según los requisitos y la arquitectura, puede haber opciones de mejora del rendimiento:

  • Puede usar vistas indexadas (matrializadas) para mejorar el rendimiento de lectura en el nivel RDBMS (servidor SQL).
    Básicamente, todo lo que necesita hacer es:
    Crear una vista regular.
    Cree un índice agrupado en esa vista .

  • El uso de un mecanismo de cobro en el nivel de aplicación mejorará el rendimiento.
    Si es posible y factible usar el cobro, tener una estrategia de efectivo como el cobro simple de perezoso lo ayudará.

NoSQL:
Hay un montón de buenos artículos sobre SQL vs NoSQL, como este y este

Los intereses de piezas de mí:

Donde utilizar NoSQL:

Si su DB es 3NF y no hace ninguna unión (solo está seleccionando un montón de tablas y colocando todos los objetos juntos, también conocido como lo que la mayoría de la gente hace en una aplicación web.

Cuando lo use, esté listo para:

  • Terminas escribiendo trabajos para hacer cosas como unir datos de diferentes tablas / colecciones, algo que un RDBMS haría por ti automáticamente.
  • Sus capacidades de consulta con NoSQL están drásticamente paralizadas. MongoDb puede ser lo más parecido a SQL, pero todavía está muy lejos. Créeme. Las consultas SQL son súper intuitivas, flexibles y potentes. Las consultas NoSql no lo son.
  • Las consultas de MongoDb pueden recuperar datos de una sola colección y aprovechar un solo índice. Y MongoDb es probablemente una de las bases de datos NoSQL más flexibles. En muchos escenarios, esto significa más viajes de ida y vuelta al servidor para buscar registros relacionados. Y luego comienza a desnormalizar los datos, lo que significa trabajos en segundo plano.
  • El hecho de que no sea una base de datos relacional significa que no tendrá restricciones de clave externa (que algunos piensan que tienen un mal desempeño) para garantizar que sus datos sean consistentes. Le aseguro que esto eventualmente creará inconsistencias de datos en su base de datos. Estar preparado. Lo más probable es que comience a escribir procesos o comprobaciones para mantener la coherencia de su base de datos, lo que probablemente no funcionará mejor que dejar que el RDBMS lo haga por usted.
  • Olvídate de frameworks maduros como hibernate.

Además de decidir usar o no usar NoSql, se puede encontrar un artículo útil sobre Comparación de DBMS NOSQL y la intención de ellos aquí, ya que algunos de ellos se centran en lecturas altas, escrituras bajas, reducción de mapas, HA ...
Echar un vistazo En la clasificación y popularidad de ellos , por categoría puede ser útil.

Mohsen Heydari
fuente
Gracias por los detalles. Verificará los enlaces y nos comunicaremos con usted.
Chandu
3

De hecho, no necesita usar un gráfico db, solo almacene los valores requeridos en un nivel superior. Es como almacenar un Ordery OrderItems. no tiene que calcular el total cada vez que se va a mostrar un pedido. En cambio, solo calcula la suma, el iva y otras cosas y las almacena con su 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?");
}

fuente
3

Sugiero mirar el patrón de segregación de responsabilidad de consulta de comando .

Básicamente, en lugar de crear un solo modelo para leer y escribir, puede crear 2 modelos diferentes. Uno optimizado para actualizar y el otro optimizado para consultas (lectura, informes, ...). Los 2 modelos están sincronizados (generalmente con una coherencia eventual) utilizando eventos de dominio (ver DDD).

Empecé a estudiar este patrón hace unos meses y realmente cambió mi forma de modelar software. No es fácil porque es un gran cambio, especialmente cuando se usa con otras técnicas como DDD y Event Sourcing. Pero vale la pena.

Hay muchos recursos disponibles en la red, busque CQRS y DDD (y eventualmente Event Sourcing).

Este patrón se puede usar tanto en SQL como en noSql.

En su caso, puede activar un evento cada vez que se cambian los nutrientes para actualizar el modelo de lectura que está optimizado para la lectura. El modelo de lectura puede ser, por ejemplo, una vista desnormalizada de los nutrientes del menú (¿por qué no usar un nosql db para una lectura eficiente)? Puede tener múltiples modelos de lectura basados ​​en las consultas que necesita realizar.

Hay algunas implicaciones al usar este enfoque, pero es muy escalable y extensible.

Davide Icardi
fuente
Este era el enfoque que estaba contemplando, pero no estaba seguro de cómo obtener los datos para el modelo de lectura (básicamente, algún proceso debería obtener los datos para el modelo de lectura).
Chandu
Por lo general, el modelo de lectura se actualiza en cada cambio. Debe implementar la interfaz de usuario con comandos (basados ​​en tareas) en lugar de utilizar operaciones crud. De esta manera, cada comando se refleja en el modelo de lectura. No necesita ejecutar otras consultas. Los comandos de diseño permiten que el sistema capture la intención real del usuario.
2

Depende en gran medida de cómo hacer para obtener los menús y los nutrientes inicialmente. ¿Por qué crees que no será eficiente?

Por lo que entiendo, vas al DB, obtienes el menú, luego vuelves, obtienes cada receta, luego vuelves y obtienes cada ingrediente y así sucesivamente. Esto es realmente ineficiente, ya que hay muchas consultas y viajes de ida y vuelta al servidor, que es la principal fuente de demoras. Esto se conoce como el problema SELECT N + 1.

Lo que debe hacer es obtener todos los datos en una sola consulta, utilizando JOINs para todas las tablas desde el menú hasta los nutrientes, para que el servidor de base de datos pueda usar todas las relaciones e índices para obtener los datos de una vez. La aplicación cliente C # solo procesa y muestra el resultado final. Hacerlo es mucho más eficiente que ir uno por uno.

En general, utilizando técnicas de consulta adecuadas y los índices correctos para consultas críticas, las bases de datos relacionales pueden funcionar muy bien en tablas grandes bajo carga.


fuente
Gracias, entiendo que depende de las uniones. Como los componentes del menú cambian ocasionalmente, no quiero ejecutar el cálculo cada vez que alguien llega a la página. En cambio, quiero un servicio en segundo plano para hacer el cálculo y simplemente puedo leerlo de una tabla cuando sea necesario. El problema con el cálculo es identificar toda la cadena cuando uno de los componentes cambia.
Chandu
Solo buscar algunas relaciones no incurre en ningún cálculo, incluso si hay 5 o 6 JOINs que no deberían ser una carga para el servidor (a menos que estemos hablando de buscar cientos o miles de filas), si la indexación es adecuada esta en su lugar. Incluso con grandes conjuntos de datos, siempre puede crear una vista de todo el resultado e incluso indexar la vista para tener el resultado precalculado, si el rendimiento se vuelve un problema.
2

Parece que ha pasado algún tiempo pensando en la mejor forma de modelar los datos para que puedan actualizarse y consultarse fácilmente. Sin embargo, ahora está en el punto donde necesita proporcionar acceso a los datos. Esas dos cosas son preocupaciones separadas.

Usted menciona que la recarga de la página está causando una nueva consulta a la base de datos. También menciona que la base de datos se actualizará ocasionalmente y, cuando sea así, desea que esas actualizaciones se muestren en la página de manera oportuna. Su mejor método para reducir la sobrecarga de consultas es no hacerlas. Si ejecuta las mismas consultas una y otra vez y obtiene los mismos resultados, ¿por qué no las almacena en caché por un tiempo? Debería poder implementar algo de almacenamiento en caché en sentido ascendente sin modificar el resto del proyecto. Recomendaría leer sobre descanso. Independientemente de si implementa el proyecto en un rdbms o nosql, los problemas con el rendimiento de este tipo se manejan mejor reduciendo la cantidad de veces que tiene que ir a la base de datos. Digamos que tiene 100 solicitudes para la misma receta en 60 segundos. Si almacena en caché durante 60 segundos, solo golpea la base de datos una vez, por lo que es una mejora de 100 veces en el rendimiento. Ver ese mismo nivel de mejora al cambiar a nosql requerirá mucho más trabajo.

Los sistemas de tipo Nosql pueden ser una gran solución cuando tiene grandes cantidades de datos o requisitos de velocidad extrema de lectura o escritura. Sin embargo, ese rendimiento adicional tiene el costo de desechar cosas como la integridad referencial.


fuente
1

Parece que para el experimento o el propósito del conocimiento desea probar Graph-DB, pero su ejemplo es claramente un ejemplo de datos jerárquicos donde podemos profundizar / descender a través de un nodo. No soy experto en Graph / Neo DB pero puedo ver que no hay mucha complejidad en la forma en que el usuario / usted puede solicitar datos de este esquema. Veo que la elección del diseño de la base de datos / esquema depende mucho de cómo y qué tipo de datos se consultarán en su contra. Como usted usa SQLSERVER "HierarchyI" D es la mejor opción desde mi punto de vista para poner estos nodos como parte de Tree.

Anup Shah
fuente
1

Mi sugerencia es pensar como una máquina y no como un humano. Puede parecer repetitivo, pero en eso son buenas las máquinas. Una cosa que debe preguntarse es "¿tengo que recuperar todos los objetos, de todos modos, para mostrarlos en mi página?" En caso afirmativo, continúe con lo que está haciendo, en comparación con la recuperación de datos, los ciclos de CPU son insignificantes cuando se realizan cálculos matemáticos simples.

Robert Co
fuente