Вложенные сущности и вычисление свойства конечных сущностей - подход SQL или NoSQL

10

Я работаю над хобби-проектом под названием Menu / Recipe Management.

Так выглядят мои сущности и их отношения.

А Nutrientимеет свойства CodeиValue

Ан Ingredientимеет коллекциюNutrients

A Recipeимеет коллекцию Ingredientsи иногда может иметь коллекцию другихrecipes

А Mealимеет коллекцию RecipesиIngredients

А Menuимеет коллекциюMeals

Отношения могут быть изображены как

Меню сущностей и отношений

На одной из страниц для выбранного меню мне нужно отобразить информацию об эффективных питательных веществах, рассчитанную на основе ее составляющих (блюда, рецепты, ингредиенты и соответствующие питательные вещества).

На данный момент я использую SQL Server для хранения данных, и я перемещаюсь по цепочке из своего кода C #, начиная с каждого приема меню и затем собирая значения питательных веществ.

Я думаю, что это неэффективный способ, так как этот расчет выполняется каждый раз, когда запрашивается страница, и составляющие время от времени меняются.

Я думал о том, чтобы иметь фоновый сервис, который поддерживает таблицу с именем MenuNutrients ( {MenuId, NutrientId, Value}) и будет заполнять / обновлять эту таблицу эффективными питательными веществами при изменении любого компонента (еда, рецепт, ингредиент).

Я чувствую, что GraphDB будет хорошо подходить для этого требования, но мое знакомство с NoSQL ограничено.

Я хочу знать, каковы альтернативные решения / подходы к этому требованию отображения питательных веществ данного меню.

Надеюсь, мое описание сценария понятно.

Chandu
источник
Сколько объектов мы говорим? Будет ли производительность действительно проблемой?
Флоп
@flup В среднем в меню может быть 8 приемов пищи, в каждом приеме пищи может быть 2 рецепта и 2 ингредиента, в каждом рецепте может быть 6-8 ингредиентов.
Чанду
Разве ваши стрелки не в неправильном направлении?
Бранко Димитриевич
Вы видели пример Nerd Dinner Entity Framework?
Акаш Кава

Ответы:

8

В зависимости от требований и архитектуры могут быть варианты улучшения производительности:

NoSql:
Есть много хороших статей о Sql против NoSql, таких как эта и эта

. Меня интересуют части:

где использовать NoSql:

Если ваша база данных 3NF и вы не выполняете никаких объединений (вы просто выбираете несколько таблиц и собираете все объекты вместе, то, что большинство людей делают в веб-приложении).

При использовании будьте готовы к:

  • Вы заканчиваете тем, что пишете задания, например, объединяете данные из разных таблиц / коллекций, то, что СУБД сделает для вас автоматически.
  • Ваши возможности запросов с NoSQL резко ограничены. MongoDb может быть ближе всего к SQL, но он все еще очень далеко позади. Доверьтесь мне. SQL-запросы очень интуитивно понятны, гибки и мощны. NoSql запросов нет.
  • Запросы MongoDb могут извлекать данные только из одной коллекции и использовать только один индекс. И MongoDb, вероятно, одна из самых гибких баз данных NoSQL. Во многих сценариях это означает больше обращений к серверу для поиска связанных записей. А затем вы начинаете отменять нормализацию данных - что означает фоновые задания.
  • Тот факт, что это не реляционная база данных, означает, что у вас не будет (что некоторые считают плохой работой) ограничений внешнего ключа для обеспечения согласованности ваших данных. Уверяю вас, это в конечном итоге приведет к несогласованности данных в вашей базе данных. Будь готов. Скорее всего, вы начнете писать процессы или проверки для поддержания согласованности вашей базы данных, что, вероятно, не будет работать лучше, чем позволить СУБД сделать это за вас.
  • Забудьте о зрелых фреймворках, таких как Hibernate.

Помимо принятия решения использовать или не использовать NoSQL, полезные статьи о NoSQL СУБД Сравнение и намерение их можно найти здесь , как некоторые из них сосредоточены на максимуме чтений, низкие записи, карта-свертка, HA ...
Посмотрев в рейтинге и популярности их по категориям может быть полезным.

Мохсен Хейдари
источник
Спасибо за подробности. Проверим ссылки и свяжемся с вами.
Чанду
3

На самом деле вам не нужно использовать граф db, просто храните необходимые значения на одном верхнем уровне. Это как хранить Orderи OrderItems. Вам не нужно рассчитывать общее количество каждый раз, когда заказ будет отображаться. Вместо этого вы просто вычисляете сумму, НДС и другие вещи и сохраняете их вместе со своими 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

Я предлагаю взглянуть на шаблон разделения ответственности командных запросов .

В основном, вместо создания одной модели для чтения и записи, вы можете создать 2 разные модели. Один оптимизирован для обновления, а другой оптимизирован для запросов (чтение, отчетность, ...). Эти две модели синхронизируются (обычно с возможной согласованностью) с использованием событий домена (см. DDD).

Я начал изучать эту модель несколько месяцев назад, и она действительно изменила мой способ моделирования программного обеспечения. Это нелегко, потому что это большой сдвиг, особенно при использовании с другими методами, такими как DDD и Event Sourcing. Но стоит того.

Есть много ресурсов, доступных в сети, поиск CQRS и DDD (и, в конечном итоге, Event Sourcing).

Этот шаблон можно использовать как для SQL, так и для noSql.

В вашем случае вы можете инициировать событие каждый раз, когда изменяются питательные вещества, чтобы обновить модель чтения, которая разрешена для чтения. Модель чтения может быть, например, денормализованным представлением питательных веществ меню (почему бы не использовать nosql db для эффективного чтения). Вы можете иметь несколько моделей чтения на основе запросов, которые вам нужно выполнить.

Этот подход имеет некоторые последствия, но он очень масштабируемый и расширяемый.

Давиде Икарди
источник
Это был подход, который я обдумывал, но не был уверен в том, как получить данные для модели чтения (в основном какой-то процесс должен получить мне данные для модели чтения).
Чанду
Обычно читаемая модель обновляется при каждом изменении. Вы должны реализовать пользовательский интерфейс с помощью команд (основанных на задачах) вместо использования операций crud. Таким образом, каждая отдельная команда отражается в модели чтения. Вам не нужно выполнять другие запросы. Проектирование команд позволяет системе улавливать реальные намерения пользователя.
2

Это во многом зависит от того, как вы получаете меню и питательные вещества на начальном этапе. Как вы думаете, почему это не будет эффективным?

Из того, что я понимаю, вы идете в БД, получаете меню, затем снова идете, получаете каждый рецепт, затем снова идете и получаете каждый ингредиент и так далее. Это действительно неэффективно, поскольку существует множество запросов и обращений к серверу, что является основным источником задержек. Это известно как проблема SELECT N + 1.

Что вам нужно сделать, это получить все данные в одном запросе, используя JOINs для всех таблиц от меню до питательных веществ, чтобы сервер БД мог использовать все связи и индексы для одновременного получения данных. Клиентское приложение C # только обрабатывает и отображает конечный результат. Делать это гораздо эффективнее, чем идти один за другим.

В целом, используя правильные методы запросов и правильные индексы для критических запросов, реляционные базы данных могут очень хорошо работать на больших таблицах под нагрузкой.


источник
Спасибо, я понимаю, что это зависит от объединений. Поскольку составляющие меню время от времени меняются, я не хочу запускать вычисления каждый раз, когда кто-то попадает на страницу. Вместо этого я хочу, чтобы фоновый сервис выполнял вычисления, и я могу просто читать их из таблицы, когда это необходимо. Проблема с расчетом заключается в идентификации всей цепочки при изменении одного из составляющих.
Чанду
Поиск нескольких отношений вообще не требует каких-либо вычислений, даже если есть 5 или 6 JOINсекунд, которые не должны быть обременительными для сервера (если мы не говорим о выборке сотен или тысяч строк), при условии правильной индексации на месте. Даже с большими наборами данных вы всегда можете построить представление для всего результата и даже индексировать представление, чтобы иметь предварительный расчет результата, если производительность когда-либо станет проблемой.
2

Похоже, вы потратили некоторое время на размышления о том, как лучше всего моделировать данные, чтобы их можно было легко обновлять и запрашивать. Однако теперь вы находитесь в той точке, где вам нужно предоставить доступ к данным. Эти две вещи являются отдельными проблемами.

Вы упоминаете, что перезагрузка страницы вызывает новый запрос к базе данных. Вы также упоминаете, что база данных будет периодически обновляться, и когда вы хотите, чтобы эти обновления отображались на странице своевременно. Лучший способ уменьшить накладные расходы на запросы - не выполнять их. Если вы выполняете одни и те же запросы снова и снова и получаете одни и те же результаты, почему бы не кешировать их какое-то время? Вы должны быть в состоянии реализовать некоторое восходящее кэширование без изменения остальной части проекта. Я бы порекомендовал почитать про отдых, Независимо от того, реализуете ли вы проект в формате rdbms или nosql, проблемы с производительностью этого типа лучше всего решать, уменьшая количество обращений к базе данных. Скажем, у вас есть 100 запросов на один и тот же рецепт за 60 секунд. Если вы кэшируете в течение 60 секунд, то вы попадаете в базу данных только один раз, так что это в 100 раз повышает производительность. Чтобы увидеть тот же уровень улучшения при переходе на nosql, потребуется гораздо больше работы.

Системы типа Nosql могут быть отличным решением, когда у вас огромный объем данных или экстремальные требования к скорости чтения или записи. Однако эта дополнительная производительность достигается за счет отказа от таких вещей, как ссылочная целостность.


источник
1

Похоже, что для эксперимента или в целях знания вы хотите попробовать Graph-DB, но ваш пример явно является примером иерархических данных, где мы можем развернуть / развернуть через узел. Я не эксперт в Graph / Neo DB, но я вижу, что пользователь / вы можете запрашивать данные из этой схемы не так уж сложно. Я вижу, что выбор дизайна базы данных / схемы очень зависит от того, как и какой тип данных будет запрашиваться. Поскольку вы используете SQLSERVER "HierarchyI", D - это лучший вариант, с моей точки зрения, чтобы поместить эти узлы как часть дерева.

Ануп Шах
источник
1

Мое предложение - думать как машина, а не как человек. Это может показаться повторяющимся, но это то, что машины хороши. Одна вещь, которую вы должны задать себе: «Нужно ли мне в любом случае извлекать каждый объект для отображения на моей странице?» Если да, продолжайте то, что вы делаете, по сравнению с поиском данных, циклы ЦП незначительны при выполнении простой математики.

Роберт Ко
источник