Projektowanie bazy danych - Czy za każdym razem zapisujesz stan czy stan obliczeniowy?

17

Powiedzmy, że mam relacyjną aplikację bazy danych oraz obiekt „użytkownika” i obiekt „wiadomości”. Teraz chcę pokazać liczbę nieprzeczytanych wiadomości dla tego użytkownika.

Jak najlepiej to zarchiwizować? Czy wprowadzam pole do użytkownika i liczę je, jeśli użytkownik otrzyma wiadomość, i zmniejszam liczbę, jeśli ją czyta? Czy też wykonuję zapytanie za każdym razem, aby obliczyć liczbę wiadomości użytkownika oznaczonych jako nieprzeczytane?

Myślę, że pierwsze podejście jest bardziej skomplikowane i podatne na błędy, ale będzie działało lepiej niż drugie podejście.

Jak to zwykle się robi lub jakie jest lepsze podejście?

Jan
źródło
1
Zależy od wielu czynników: czy twoja baza danych jest podzielona na partycje? Ile oczekujesz wierszy / użytkownika? Jakiego rozmiaru oczekujesz DB (lub ilu użytkowników ogółem)? Ile oczekujesz na sekundę? Wszystko to nie musi być dokładne, ale kilka szorstkich pomysłów ...
Omer Iqbal
10
+1 To klasyczne pytanie dotyczące relacyjnej bazy danych. Normalizować, czy nie normalizować? Oto jest pytanie. Czy to szlachetniejszy w schemacie, by cierpieć z powodu procy i strzały oburzającego powielania, czy podejmować wyzwalacze, a stosując je, zakończyć je?
Ross Patterson
Spieram się, czy to nie jest klasyczny Rel. db. pytanie, powinna już być odpowiedź na stronie, powinna być zamknięta jako DUP, lub nie mamy odpowiedzi i należy ją pozostawić otwartą.
mattnz

Odpowiedzi:

14

Jak to zwykle się robi lub jakie jest lepsze podejście?

Najlepszym rozwiązaniem jest wypróbowanie go najpierw bez dodatkowego pola, zmierzenie wydajności, a jeśli naprawdę okaże się zbyt wolne, spróbuj zoptymalizować. Może to oznaczać przejście na pierwsze podejście przy użyciu dodatkowego pola, ale należy również rozważyć przetestowanie innych opcji, na przykład umieszczenie dodatkowego indeksu w połączonych polach („nieprzeczytane”, „ID użytkownika”) w wiadomościach.

Doktor Brown
źródło
2
Najlepszym rozwiązaniem jest (najpierw należy zastosować prostszą metodę). Ogólne zasady są lepsze niż szczegółowe, fwiw. (+1 za „test!”.)
DougM
9

Rozwiązaniem podręcznika zgodnym z teorią bazy danych byłoby brak w bazie danych wartości zależnych od wartości innych danych, ponieważ są to zależności przechodnie . Posiadanie pól, które są wartościami obliczonymi na podstawie innych pól, stanowi naruszenie normalizacji, ponieważ prowadzi do zbędnych informacji.

Jednak czasami to, co mówi podręcznik i jaka jest najbardziej praktyczna metoda w praktyce, różni się. Zliczanie liczby nieprzeczytanych wiadomości przy każdym wyświetleniu strony może być dość kosztowną operacją. Buforowanie liczby w usertabeli -t byłoby znacznie lepsze dla wydajności. Kosztem byłoby istnienie niekonsekwencji w bazie danych: Możliwe, że wiadomość zostanie usunięta, dodana lub przeczytana bez pamiętania o aktualizacji również licznika nieprzeczytanego.

Philipp
źródło
4
Problem z spójnością można łatwo polizać za pomocą wyzwalaczy, które dostosowują licznik do INSERTlub DELETE. (Lub UPDATE, aby uwzględnić zmianę właściciela wiadomości). Dobry DBMS wykona operację i uruchomi wyzwalacze w tej samej transakcji, więc wszystko albo nic się nie wydarzy.
Blrfl
4

Potencjalnym problemem jest wydajność i nie masz jeszcze problemu z wydajnością. Istnieje wiele rzeczy, które możesz zrobić w zależności od wybranej bazy danych, aby poradzić sobie z tym w rozwiązaniu nr 1: indeksowanie, sprzęt, buforowanie itp. Wszystko to zależy od tego, jak często użytkownik musi uzyskać bieżącą liczbę nieprzeczytanych wiadomości. Wiele z tych wyborów nie wymaga niestandardowego kodowania po stronie aplikacji, więc możesz je zaimplementować ze zmianą kodu lub bardzo niewiele. Ułatwia rozwój dzięki aplikacji.

Gdy użytkownik się połączy / zaloguje, odliczanie z bazy danych nie jest takie złe. Czy Twoja aplikacja będzie utrzymywać stale aktualizowaną listę wiadomości, takich jak e-mail? Otrzymanie nieprzeczytanej liczby z tego miejsca nie wymaga kolejnej podróży do bazy danych, a uzyskanie nowych wiadomości i tak zajmie podróż do bazy danych.

Wybierasz się do bazy danych za każdym razem, gdy czytany jest komunikat w celu oznaczenia IsRead? wystarczy pole bez przeliczenia innego pola.

W przypadku rozwiązania nr 2 (utrzymywanie liczby w polu / na dysku), czy potrzebujesz procedury okresowej przebudowy / przeliczenia tego pola, gdy wystąpi problem? I zawsze są problemy. Zamierzasz zawrzeć to wszystko w transakcji? Za każdym razem, gdy ktoś wysyła komuś wiadomość, może się nie powieść, ponieważ nie może zaktualizować UnreadCount użytkownika odbierającego z powodu blokady tabeli użytkowników? A może zamierzasz utworzyć osobną tabelę dla tego pola?

JeffO
źródło
+1 za wzmiankę o problemach z wydajnością przy aktualizowaniu pól zliczania
winkbrace
0

Chciałbym to zrobić, wykonując zapytanie za każdym razem, czyli twoje drugie podejście. Upewnij się tylko, że dodajesz indeks do tabeli komunikatów w kolumnie, która działa jak klucz obcy do tabeli użytkowników, aby poprawić wydajność zapytania.

Następnie, jak mówi Doc, zmierz skuteczność tego podejścia, a następnie będziesz w stanie stwierdzić, czy musisz wybrać inną ścieżkę.

Jose B.
źródło