Lubi lub głosuje na posty

10

Tworzę mały program, w którym użytkownicy publikują posty lub piszą blogi. W tych postach inni użytkownicy mogą lubić lub nie lubić postu jak na Facebooku lub głosować w górę lub w dół głosować jak w przypadku stackoverflow. Chciałbym poznać dobrą strukturę bazy danych, która jest powszechnie używana i program działa skutecznie z tą strukturą. Mam dwie opcje

Pierwszy

Poczta:

id   head   message   datepost   likes   dislikes
1     ab    anchdg     DATE      1,2,3   7,55,44,3

W powyższy sposób idjest postid. W kolumnie „ 1,2,3Lubię to” znajduje się identyfikator użytkownika, który polubił lub ocenił wpis lub blog. 7,55,44,3to identyfikator użytkowników, którzy nie lubili lub nie ocenili posta lub bloga.

druga

Poczta:

id    head  message   datepost
1     ab    anchdg     DATE

Lubi:

id    postid    userid
1       1         1
2       2         2

Nie lubi:

id    postid    userid
1       1         7
2       1         55

W ten sposób muszę utworzyć dwie osobne tabele dla ocen pozytywnych i negatywnych. W ten sposób tabele, czyli Likes&, Dislikeszostaną mocno wypełnione. Może to spowalniać pracę tabeli.

Chciałbym więc wiedzieć, który jest lepszy i standardowy sposób na wykonanie tego zadania?

Harshit Shrivastava
źródło
4
Zakładam, że użytkownik nie może lubić i nie lubić postu? Jeśli tak, miałbym jedną tabelę dla polubień i nielubień, z kolumną BIT (1 dla lajków, 0 dla lajków).
dwjv
1
Lub 1 i -1 dla łatwiejszych sum
jkavalik
1
@dwjv W pierwszym przykładzie użytkownik 3 polubił i nie lubił postu.
Dan Henderson

Odpowiedzi:

20

Problem, który napotykasz, znany jest jako „normalne formy” baz danych, zwłaszcza pierwsza normalna forma. https://en.wikipedia.org/wiki/First_normal_form .

Twoja baza danych z połączonymi identyfikatorami użytkowników (pierwsza wersja) nie jest w pierwszej normalnej formie.

Zobacz https://en.wikipedia.org/wiki/Database_normalization, aby dowiedzieć się, dlaczego i jak normalizację uważa się ogólnie za dobrą.

W pierwszym przykładzie zapytanie „użytkownik 4 nie lubi już postu” staje się skomplikowane. Będzie musiał wykonać operacje na łańcuchach, które będą musiały wziąć pod uwagę skutki uboczne i przypadki narożne (użytkownik jest jedynym użytkownikiem „lubiącym”, użytkownik jest ostatnim lubiącym użytkownikiem, użytkownik znajduje się w środku lubiącego ciągu użytkownika). Uważałbym to za złe. Nie rób tego Użyj znormalizowanego projektu.

Re: baza danych staje się ciężka

Jeśli masz post, który ma 4 miliony polubień, w projekcie bazy danych 1 miałbyś jeden wiersz z kolumną „polubienia” o szerokości co najmniej 4 milionów znaków (ponieważ będziesz potrzebował przecinka jako znaków oddzielających). Będziesz wtedy musiał wykonać operacje na łańcuchach o szerokości czterech milionów cyfr. Jest to bardzo nieskuteczne i powolne.

Z drugiej strony bazy danych są zaprojektowane do obsługi milionów wierszy. Mamy bazy danych zawierające kilkaset milionów wierszy i count () - operacje są szybkie. Ekstremalnie szybko. Więc nie, to nie będzie wąskie gardło wydajności.

Kolejnym zagadnieniem byłaby czytelność i łatwość konserwacji.

Na przykład powiedz mi, co robią te 2 instrukcje:

select count(*)
from posts
inner join likes on posts.postid = likes.postid
where postid = 7

select len(likes) - len(replace(likes, ',', ''))
from posts
where postid = 7
til_b
źródło
Jak już wspomniałem, jeśli w stole występują miliony lub miliardy polubień, to czy stół nie stałby się ciężki? Czy nie zajmie dużo czasu przeszukanie tabeli z rekordowymi rekordami, ponieważ stół zapełni się bardzo szybko?
Harshit Shrivastava
6
@HarshitShrivastava mysql może obsługiwać proste tabele miliardów wierszy, ale wyobraź sobie, że miliardy (dis) lubią się jako ciągi w tabeli użytkowników - z którymi może być jeszcze więcej i ciężko z nimi pracować.
jkavalik
3
Jedną rzeczą @ til_b, o której nie wspomina się bezpośrednio (ale zwykle sugeruje się to za pomocą normalnych formularzy), jest to, że drugi projekt, odpowiednio zaimplementowany, pozwoli bazowemu silnikowi bazy danych zachować spójność referencyjną, czego nie można zrobić przy pierwszym wzorcu projektowym. Zasadniczo oznacza to, że jeśli użytkownik 4 zostanie usunięty, baza danych wyczyści połączone dane, ponieważ wie, które rekordy zależą od rekordu użytkownika 4. Pierwszy projekt jest do tego niezdolny, ponieważ baza danych intuicyjnie nie wie, jak zarządzać relacją w ciągu.
David Antaramian
9

Drugi sposób jest o wiele lepszy, ponieważ możesz łatwo dodać lub usunąć polubienie / niechęć.

Ale powinieneś zmodyfikować swoje drugie rozwiązanie, używając jednej tabeli do polubienia lub nie lubienia.
Kolumny tabeli like / dislike powinny mieć id, postid, userid i inną dla wartości like lub dislike np. 1 dla dislike i -1 dla like.

Ustaw post_id i user_id jako złożony klucz podstawowy i działa dobrze.

Rozmiar stołu będzie się z czasem powiększał. ale masz tylko dwie prawdziwe kolumny. Identyfikator i wartość like / dislike. Identyfikator postid i identyfikator użytkownika są z nim tylko powiązane i przechowywane w tabeli użytkownika i posta.

Julian S.
źródło
3
Trzeba było user_id, post_ida valuew tabeli. Nie ma potrzeby oddzielnej idkolumny.
jkavalik
3
Jak sugeruje komentarz @ jkavalik do pytania, 1 i -1 byłyby prawdopodobnie lepszymi wartościami dla like i dislike niż 1 i 2, ponieważ umożliwiłyby obliczenie całkowitego wyniku za pomocą prostej sumy tabeli, zamiast odejmowania liczby wiersze z „2” z liczby wierszy z „1”.
Dan Henderson
@DanHenderson: Coś jak polubienia - nie lubienie może być nieco szybsze niż suma. (To powiedziawszy jednak, zadziała również z 1 i -1.)
cHao
z entuzjazmem, jak byś to zrobił, gdybyś powiedział jeszcze 2 działania, takie jak miłość i gniew? mam na myśli 1 dla
lajków
Jeśli nie chcesz sumniczego, możesz ustawić miłość = 2 i gniew = 3
Julian S