it-swarm.dev

Przechowywanie a obliczanie wartości zagregowanych

Czy istnieją jakieś praktyczne wytyczne 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 tabeli Ratings. Alternatywnie mógłbym zapisać średnią ocenę w tabeli Widget. Dzięki temu nie musiałbym obliczać 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
100
BenV

Zależy. Wstępne obliczanie wartości zagregowanych nakłada większe obciążenie na zapisy, wyprowadzenie ich utrudnia odczytywanie

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 został zaprojektowany 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. Zapewni to „wystarczająco dobrą” średnią przy jednoczesnym zachowaniu wydajności zapisu i odczytu.

W żadnym wypadku nie powinieneś traktować wyprowadzonej kolumny jak „normalnej” kolumny: upewnij się, że dane przedstawione w „widoku” Widżetów znajdują się gdzie indziej w tabeli, tak że cała Tuple może 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) względem zestawu danych o normalnym rozmiarze i zmaterializowanego widoku.

60

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

Tak więc, jeśli 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, w których statystyki zmieniają się z każdą sekundą, ale masz tylko trzy osoby, które mają do nich dostęp i patrzą na to tylko kilka razy dziennie, bardziej prawdopodobne jest, że obliczę w locie. (chyba że zajmie to kilka minut, aby obliczyć, że posiadanie nieaktualnych danych w pierwszej kolejności nie jest wielką sprawą ... a mój szef każe mi generować coś z crona co godzinę, więc nie ma czekać, kiedy chce na to spojrzeć).

11
Joe

Użyj tabeli StaleWidgets jako kolejki „nieprawidłowych” (do ponownego obliczenia) widżetów. Użyj innego wątkowego (asynchronicznego) zadania, 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
  • ...
4
garik

Sugerowałbym obliczanie w locie, jeśli obliczanie nie jest zbyt kłopotliwe, 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 . na przykład ustaw tę kolumnę na wartość true za każdym razem, gdy należy wykonać ponowne obliczenie, ale nie wykonuj ponownego obliczania, a po ponownym obliczeniu 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ń.

2
techExplorer

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ść.

2
Adrian Martinez