Elementy zagnieżdżone i obliczenia właściwości encji liścia - podejście SQL lub NoSQL


10

Pracuję nad projektem hobby o nazwie Menu / Recipe Management.

Tak wyglądają moje byty i ich relacje.

A Nutrientma właściwości CodeiValue

An Ingredientma kolekcjęNutrients

A Recipema kolekcję Ingredientsi czasami może mieć kolekcję innychrecipes

A Mealma kolekcję RecipesiIngredients

A Menuma kolekcjęMeals

Relacje można przedstawić jako

Elementy menu i relacje

Na jednej ze stron, dla wybranego menu muszę wyświetlić informacje o skutecznych składnikach odżywczych obliczonych na podstawie jego składników (posiłków, przepisów, składników i odpowiednich składników odżywczych).

W tej chwili używam SQL Server do przechowywania danych i nawiguję łańcuch z mojego kodu C #, zaczynając od każdego posiłku w menu, a następnie agregując wartości odżywcze.

Myślę, że nie jest to skuteczny sposób, ponieważ obliczenia są przeprowadzane za każdym razem, gdy strona jest żądana, a składniki czasami się zmieniają.

Myślałem o posiadaniu usługi w tle, która utrzymuje tabelę o nazwie MenuNutrients ( {MenuId, NutrientId, Value}) i będzie wypełniać / aktualizować tę tabelę skutecznymi składnikami odżywczymi, gdy którykolwiek ze składników (posiłek, przepis, składnik) zmieni się.

Wydaje mi się, że GraphDB dobrze pasuje do tego wymogu, ale moja ekspozycja na NoSQL jest ograniczona.

Chcę wiedzieć, jakie są alternatywne rozwiązania / podejścia do tego wymogu wyświetlania składników odżywczych w danym menu.

Mam nadzieję, że mój opis scenariusza jest jasny.


Ile przedmiotów mówimy? Czy wydajność naprawdę będzie problemem?
flup

@flup Menu może mieć średnio 8 posiłków, każdy posiłek może mieć 2 przepisy kulinarne i 2 składniki, każdy przepis może zawierać 6-8 składników.
Chandu,

Czy twoje strzały nie są w złym kierunku?
Branko Dimitrijevic

Czy widziałeś próbkę Nerd Dinner Entity Framework?
Akash Kava,

Odpowiedzi:


8

W zależności od wymagań i architektury mogą istnieć opcje poprawy wydajności:

  • Możesz użyć widoków indeksowanych (zmaterializowanych) Aby poprawić wydajność odczytu na poziomie RDBMS (serwer Sql).
    Zasadniczo wszystko, co musisz zrobić, to:
    Utwórz zwykły widok.
    Utwórz indeks klastrowany w tym widoku .

  • Korzystanie z mechanizmu płatności na poziomie aplikacji poprawi wydajność.
    Jeśli jest to możliwe i wykonalne, skorzystaj z strategii gotówkowej, takiej jak singleton leniwa gotówka .

NoSql:
Istnieje wiele dobrych artykułów na temat Sql vs NoSql, takich jak ten i ten

Części mnie interesują:

Gdzie używać NoSql:

Jeśli twoja baza danych to 3NF i nie wykonujesz żadnych połączeń (po prostu wybierasz kilka tabel i łączysz wszystkie obiekty razem, AKA, co większość ludzi robi w aplikacji internetowej.

Po użyciu należy być gotowym do:

  • W końcu piszesz zadania, takie jak łączenie danych z różnych tabel / kolekcji, co RDBMS zrobi dla ciebie automatycznie.
  • Twoje możliwości zapytań w NoSQL są drastycznie sparaliżowane. MongoDb może być najbliżej SQL, ale wciąż jest bardzo daleko w tyle. Zaufaj mi. Zapytania SQL są bardzo intuicyjne, elastyczne i wydajne. Zapytania NoSql nie są.
  • Zapytania MongoDb mogą pobierać dane tylko z jednej kolekcji i korzystać z tylko jednego indeksu. A MongoDb jest prawdopodobnie jedną z najbardziej elastycznych baz danych NoSQL. W wielu scenariuszach oznacza to więcej podróży w obie strony na serwer w celu znalezienia powiązanych rekordów. A potem zaczynasz od normalizować dane - co oznacza zadania w tle.
  • Fakt, że nie jest to relacyjna baza danych, oznacza, że ​​nie będziesz mieć (zdaniem niektórych złej wydajności) ograniczeń klucza obcego, aby zapewnić spójność danych. Zapewniam cię, że w końcu spowoduje to niespójność danych w Twojej bazie danych. Być przygotowanym. Najprawdopodobniej zaczniesz pisać procesy lub kontrole, aby zachować spójność bazy danych, co prawdopodobnie nie będzie lepsze niż pozwolenie RDBMS na wykonanie tego za Ciebie.
  • Zapomnij o dojrzałych ramach, takich jak hibernacja.

Przy podejmowaniu decyzji o użyciu lub nie używać NoSQL, pomocny artykuł na NoSQL DBMS porównanie i zamiaru z nich można znaleźć tutaj , ponieważ niektóre z nich skupiają się na wysokiego brzmi low pisze map-reduce, HA ...
zaglądając w rankingu i popularności , według kategorii mogą być przydatne.


Dziękuję za szczegóły. Sprawdzę linki i skontaktuję się z Tobą.
Chandu

3

W rzeczywistości nie musisz używać db db wykresu, po prostu przechowuj wymagane wartości na jednym wyższym poziomie. To jest jak przechowywanie Orderi OrderItems. nie musisz obliczać sumy za każdym razem, gdy zamówienie ma zostać wyświetlone. Zamiast tego po prostu obliczasz sumę, VAT i inne rzeczy i przechowujesz je ze sobą 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

Sugeruję przyjrzeć się wzorowi podziału odpowiedzialności za zapytania dowodzenia .

Zasadniczo zamiast tworzyć jeden model do odczytu i zapisu, można utworzyć 2 różne modele. Jeden zoptymalizowany pod kątem aktualizacji, a drugi zoptymalizowany pod kątem zapytań (odczyt, raportowanie ...). Dwa modele są zsynchronizowane (zwykle z ewentualną spójnością) przy użyciu zdarzeń domenowych (patrz DDD).

Zacząłem studiować ten wzór kilka miesięcy temu i to naprawdę zmieniło mój sposób modelowania oprogramowania. Nie jest to łatwe, ponieważ jest to duża zmiana, szczególnie w połączeniu z innymi technikami, takimi jak DDD i Event Sourcing. Ale warto.

Istnieje wiele zasobów dostępnych w sieci, szukaj CQRS i DDD (i ewentualnie Sourcing zdarzeń).

Tego wzorca można używać zarówno w SQL, jak i noSql.

W twoim przypadku możesz uruchomić zdarzenie za każdym razem, gdy zmieniane są składniki odżywcze, aby zaktualizować model odczytu, który jest zoptymalizowany do odczytu. Model odczytu może być na przykład zdenormalizowanym widokiem składników odżywczych menu (dlaczego nie używać db nosql do wydajnego odczytu). Możesz mieć wiele modeli odczytu opartych na zapytaniach, które musisz wykonać.

Takie podejście ma pewne implikacje, ale jest ono bardzo skalowalne i rozszerzalne.


Takie podejście rozważałem, ale nie byłem pewien, jak uzyskać dane dla modelu odczytu (w zasadzie jakiś proces powinien dostarczyć mi dane do modelu odczytu).
Chandu,

Zwykle model odczytu jest aktualizowany przy każdej zmianie. Powinieneś wdrożyć interfejs użytkownika za pomocą poleceń (opartych na zadaniach) zamiast korzystania z operacji crud. W ten sposób każde polecenie jest odzwierciedlane w modelu odczytu. Nie musisz wykonywać innych zapytań. Polecenia projektowe pozwalają systemowi uchwycić prawdziwe zamiary użytkownika.

2

Zależy to w dużej mierze od tego, jak początkowo uzyskać menu i składniki odżywcze. Jak myślisz, dlaczego to nie będzie skuteczne?

Z tego, co rozumiem, idziesz do DB, dostajesz menu, a następnie idziesz ponownie, dostajesz każdy przepis, a następnie idziesz ponownie i dostajesz każdy składnik i tak dalej. Jest to naprawdę nieefektywne, ponieważ istnieje wiele zapytań i podróży w obie strony do serwera, który jest głównym źródłem opóźnień. Jest to znane jako problem WYBIERZ N + 1.

To, co powinieneś zrobić, to pobrać wszystkie dane w jednym zapytaniu, używając JOINs dla wszystkich tabel od menu aż do składników odżywczych, aby serwer DB mógł użyć wszystkich relacji i indeksów, aby uzyskać wszystkie dane naraz. Aplikacja kliencka C # przetwarza tylko i wyświetla wynik końcowy. Jest to o wiele bardziej wydajne niż przechodzenie jeden po drugim.

Zasadniczo, stosując odpowiednie techniki zapytań i odpowiednie indeksy dla zapytań krytycznych, relacyjne bazy danych mogą bardzo dobrze działać na dużych tabelach pod obciążeniem.


Dzięki, rozumiem, że to zależy od złączeń. Ponieważ elementy menu zmieniają się czasami, nie chcę uruchamiać obliczeń za każdym razem, gdy ktoś wejdzie na stronę. Zamiast tego chcę, aby usługa działająca w tle wykonała obliczenia i w razie potrzeby mogę po prostu odczytać ją z tabeli. Problemem w obliczeniach jest identyfikacja całego łańcucha, gdy zmienia się jeden ze składników.
Chandu

Samo przeszukanie kilku relacji w ogóle nie pociąga za sobą żadnych obliczeń, nawet jeśli jest 5 lub 6 JOINs, które nie powinny stanowić obciążenia dla serwera (chyba że mówimy o pobieraniu setek lub tysięcy wierszy), jeśli właściwe indeksowanie jest na miejscu. Nawet w przypadku dużych zbiorów danych zawsze możesz zbudować widok dla całego wyniku, a nawet zindeksować widok, aby wynik był wstępnie obliczony, jeśli wydajność kiedykolwiek stanie się problemem.

2

Wygląda na to, że poświęciłeś trochę czasu na zastanowienie się, jak najlepiej modelować dane, aby można je było łatwo aktualizować i uzyskiwać zapytania. Jednak teraz jesteś w punkcie, w którym musisz zapewnić dostęp do danych. Te dwie rzeczy stanowią odrębne obawy.

Wspomniałeś, że ponowne załadowanie strony powoduje nowe zapytanie do bazy danych. Wspominasz również, że baza danych będzie od czasu do czasu aktualizowana i kiedy chcesz, aby aktualizacje te były wyświetlane na stronie w odpowiednim czasie. Najlepszą metodą zmniejszenia obciążenia związanego z zapytaniami jest ich nie robienie. Jeśli ciągle uruchamiasz te same zapytania i uzyskujesz te same wyniki, dlaczego nie buforujesz ich przez chwilę? Powinieneś być w stanie zaimplementować buforowanie w górę, bez modyfikowania reszty projektu. Poleciłbym przeczytać o odpoczynku. Niezależnie od tego, czy projekt zostanie wdrożony w rdbms lub nosql, problemy z wydajnością tego typu najlepiej rozwiązywać, zmniejszając liczbę razy, kiedy trzeba przejść do bazy danych. Załóżmy, że masz 100 próśb o ten sam przepis w 60 sekund. Jeśli buforujesz przez 60 sekund, trafiasz do bazy danych tylko raz, co oznacza 100-krotną poprawę wydajności. Aby zobaczyć ten sam poziom poprawy po przejściu na nosql, będzie wymagało dużo więcej pracy.

Systemy typu Nosql mogą być świetnym rozwiązaniem, gdy masz ogromne ilości danych lub ekstremalne wymagania dotyczące prędkości odczytu lub zapisu. Jednak ta dodatkowa wydajność wiąże się z kosztem wyrzucenia takich rzeczy, jak integralność referencyjna.


1

Wydaje się, że do celów eksperymentu lub wiedzy chcesz wypróbować Graph-DB, ale twój przykład jest wyraźnie przykładem danych hierarchicznych, w których możemy Drill-Down / Up przez węzeł. Nie jestem ekspertem od Graph / Neo DB, ale widzę, że nie ma dużej złożoności w sposobie, w jaki użytkownik / możesz żądać danych z tego schematu. Widzę, że wybór projektu bazy danych / schematu jest bardzo zależny od tego, w jaki sposób i jakiego rodzaju dane będą do niego kierowane. Podczas korzystania z SQLSERVER „Hierarchia I” D jest z mojego punktu widzenia najlepszą opcją umieszczenia tych węzłów jako części drzewa.


1

Proponuję myśleć jak maszyna, a nie jak człowiek. Może się to wydawać powtarzalne, ale w tym, w czym są dobre maszyny. Jedną z rzeczy, które musisz sobie zadać, jest: „czy mimo wszystko muszę pobrać każdy obiekt, aby wyświetlić go na mojej stronie?” Jeśli tak, kontynuuj to, co robisz, w porównaniu do pobierania danych, cykle procesora są pomijalne podczas wykonywania prostej matematyki.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.