Przechowywanie a obliczanie wartości zagregowanych

96

Czy istnieją jakieś praktyczne wskazówki lub reguły określające, kiedy przechowywać wartości zagregowane, a kiedy obliczać je w locie?

Załóżmy na przykład, że mam widżety, które użytkownicy mogą oceniać (patrz schemat poniżej). Za każdym razem, gdy wyświetlam widżet, mogłem obliczyć średnią ocenę użytkowników z Ratingstabeli. Alternatywnie mógłbym zapisać średnią ocenę na Widgetstole. Pozwoliłoby mi to uniknąć konieczności obliczania oceny za każdym razem, gdy wyświetlam widżet, ale musiałbym ponownie obliczać średnią ocenę za każdym razem, gdy użytkownik ocenia widżet.

Ratings       Widgets
---------     -------
widget_id     widget_id
user_id       name              
rating        avg_rating  <--- The column in question
BenV
źródło

Odpowiedzi:

58

To zależy. Wstępne obliczanie wartości zagregowanych powoduje większe obciążenie zapisów, wyprowadzenie ich utrudnia odczyt

Jeśli często uzyskujesz dostęp do wartości pochodnej, wstępne obliczenia są ważnym krokiem de-normalizacji. Jednak w tym przypadku zalecam użycie widoku zmaterializowanego (widok zapisany na dysk, połączony wyzwalaczem z tabelami nadrzędnymi). Widok zmaterializowany służy do przechowywania często zadawanych, ale żmudnych danych, i jest użyteczny w przypadku dużej liczby zapisów i niskiej liczby odczytów.

W scenariuszu z wysokim zapisem i wysokim odczytem rozważ zadanie w tle, które naśladuje efekty zmaterializowanego widoku, ale w czasie krótszym niż w czasie rzeczywistym. Będzie to stanowić „wystarczająco dobrą” średnią przy jednoczesnym zachowaniu wydajności zapisu i odczytu.

W żadnym wypadku nie należy traktować wyprowadzonej kolumny jak kolumny „normalnej”: upewnij się, że dane przedstawione w „widoku” Widżetów znajdują się gdzie indziej w tabeli, tak aby cała krotka mogła być uzyskana przez dowolne procesy, które umieścisz. To pytanie jest również ściśle związane z bazą danych (i wersją bazy danych), dlatego zalecam testowanie wydajności agregatu (z odpowiednimi indeksami) w stosunku do zestawu danych normalnej wielkości i zmaterializowanego widoku.

Brian Ballsun-Stanton
źródło
Uważam, że ta dyskusja jest bardzo pomocna w odniesieniu do Zmaterializowanych poglądów. Jest dostosowany do Oracle, ale można go zrozumieć ogólnie. Dla takich jak ja, którzy pochodzą z tła MySQL, widok MySQL różni się od widoku zmaterializowanego, jest wirtualny i nie przechowuje na dysku (o czym mówiłem w linku, który podałem).
Siddhartha
entuzjastycznie! właśnie miałem zadać dokładne pytanie, muszę przechowywać wskaźniki takie jak SMA, EMA, WMA, RSI itp. i wymagają one intensywnych obliczeń, tworzyłem obecnie tabelę, którą do tej pory ręcznie odświeżałem, wskaźniki te zmieniają się o 100% za każdym razem z nadchodzą nowe dane, co jest dobrą strategią na ich utrzymanie, wiem, że widoki całkowicie rozerwą bazę danych, jeśli wszyscy zaczną sprawdzać widoki w lewo i w prawo
PirateApp
11

Jak często trzeba obliczać / wyświetlać wartości w stosunku do tego, jak często liczby bazowe są zmieniane / aktualizowane.

Jeśli więc masz witrynę z 10 000 odwiedzin dziennie, która wyświetla wartość, która będzie się zmieniać tylko raz na godzinę, obliczę ją, gdy zmienią się wartości bazowe (może to być wyzwalacz bazy danych, cokolwiek).

Jeśli masz narzędzie do przeglądania statystyk, gdzie statystyki zmieniają się z każdą sekundą, ale tylko trzy osoby mają dostęp i patrzą na to tylko kilka razy dziennie, bardziej prawdopodobne jest, że obliczę w locie. (chyba że zajmuje to kilka minut, aby obliczyć, że posiadanie nieaktualnych danych w pierwszej kolejności nie jest wielkim problemem ... a mój szef mówi mi, żebym generował coś z crona co godzinę, więc nie ma czekać, kiedy będzie chciał na to spojrzeć.)

Joe
źródło
co 15 minut, 10 wskaźników, które zmieniają się w 100% przy 1000 wierszach na
metr
1
@PirateApp i ile razy jest oglądany w średnio 15-minutowym oknie? Możesz także wygenerować go na pierwsze żądanie w oknie 15-minutowym, a następnie buforować go dla osób, które wciąż borykają się z przeładowaniem
Joe
będzie na stronie, więc zakładam, że na początek zobaczy ją co najmniej 10000 osób, strona nie jest na żywo, więc nie ma aktualnych danych o zachowaniu użytkowników
PirateApp
1
Problemem jest to, ile żądań w stosunku do tego, jak często się zmienia. Jeśli więc wstępnie wygenerujesz coś, co będzie widoczne 10 000 razy, zanim zmienią się dane bazowe, to tak, wstępnie wygeneruj. Jeśli jest oglądany tylko raz lub mniej niż raz (ponieważ dane zmieniają się tak szybko lub ponieważ strona jest rzadko oglądana), to nie.
Joe
4

Użyj tabeli StaleWidgets jako kolejki „niepoprawnych” (do przeliczenia) widżetów. Użyj innego zadania wątkowego (asynchronicznego), które może przeliczyć te wartości. Okres lub moment ponownych obliczeń zależy od wymagań systemowych:

  • tylko w trakcie czytania,
  • pod koniec miesiąca
  • dla niektórych użytkowników na początku dnia
  • ...
garik
źródło
1
Jak w takim razie dostają się do nieaktualnej kolejki?
jcolebrand
2
@jcolebrand .. w momencie wstawiania / usuwania oceny (tabela ocen) dla niektórych widgetów. W tej chwili średnia wartość w tabeli Widżetów staje się nieprawidłowa, dlatego musimy wstawić do tabeli rekord StaleWidgets, który ma tylko jedną kolumnę - widget_id. Użyj wyzwalacza lub zapisanego proc, który wstawia rekord do tabeli ocen lub twojego wariantu oczywiście.
garik
2

Sugerowałbym obliczanie w locie, jeśli obliczanie nie jest zbyt uciążliwe, a jeśli masz złożoną kalkulację i częstą aktualizację, ale nie odczytujesz frequnet niż możesz przechowywać obliczone dane i masz dodatkową kolumnę (bool), która będzie przechowywać, czy ponowne obliczenie jest wymagane, czy nie . np. ustaw tę kolumnę na wartość true za każdym razem, gdy należy wykonać ponowne obliczenie, ale nie wykonuj ponownego obliczania, a gdy wykonujesz ponowne obliczanie, ustaw tę kolumnę jako fałsz (będzie to oznaczać, że obliczona wartość jest najnowsza i nie jest nieaktualna).

W ten sposób nie będziesz musiał ponownie obliczać za każdym razem, będziesz obliczać tylko wtedy, gdy będziesz musiał odczytać, a ponowne przeliczenie wartości kolumny jest prawdziwe. W ten sposób zaoszczędzisz wiele przeliczeń.

techExplorer
źródło
2

W szczególności w przypadku przypadku istnieje inne rozwiązanie, w którym nie trzeba dodawać wszystkich ocen i dzielić go przez sumę, aby znaleźć średnią. Zamiast tego możesz mieć inne pole, które zawiera sumę recenzji, dlatego za każdym razem, gdy dodajesz ocenę, obliczasz nową średnią za pomocą (avg_rating × total + new_rating) / total, jest to znacznie szybsze niż agregowanie i zmniejsza odczyty dysku, ponieważ nie muszą mieć dostępu do wszystkich wartości oceny. Podobne rozwiązania mogą mieć zastosowanie w innych przypadkach.

Minusem tego jest to, że nie jest to transakcja typu acid, więc możesz zakończyć z nieaktualną oceną. Ale nadal możesz to rozwiązać za pomocą wyzwalaczy w bazie danych. Innym problemem jest to, że baza danych nie jest już znormalizowana, ale nie bój się denormalizować danych w zamian za wydajność.

Adrian Martinez
źródło