Jestem programistą. Uwielbiam kodować, ale nie znoszę baz danych ... Obecnie tworzę stronę internetową, na której użytkownik będzie mógł oznaczyć podmiot jako polubiony (jak na FB), otagować go i skomentować .
Utknąłem na projektowaniu tabel bazy danych do obsługi tej funkcji. Rozwiązanie jest banalne, jeśli możemy to zrobić tylko dla jednego rodzaju rzeczy (np. Zdjęć). Ale muszę to włączyć dla 5 różnych rzeczy (na razie, ale zakładam też, że ta liczba może rosnąć w miarę wzrostu całej usługi).
Znalazłem tutaj kilka podobnych pytań, ale żadne z nich nie ma satysfakcjonującej odpowiedzi, więc zadaję to pytanie ponownie.
Pytanie brzmi, jak prawidłowo, wydajnie i elastycznie zaprojektować bazę danych, aby mogła przechowywać komentarze dla różnych tabel , polubień dla różnych tabel i dla nich tagi . Jakiś wzorzec projektowy jako odpowiedź będzie najlepszy;)
Opis szczegółowy : Mam tabelę User
z danymi użytkownika i jeszcze 3 tabele : Photo
ze zdjęciami , Articles
z artykułami , Places
z miejscami . Chcę umożliwić każdemu zalogowanemu użytkownikowi:
skomentuj dowolną z tych 3 tabel
oznacz dowolne z nich jako lubiane
oznacz dowolne z nich jakimś tagiem
Chcę też policzyć liczbę polubień dla każdego elementu i ile razy ten konkretny tag został użyty.
1 st podejście :
a) W przypadku tagów będę utworzyć tabelę Tag [TagId, tagName, tagCounter]
, a następnie będzie utworzyć wiele do wielu relacje tabel dla: Photo_has_tags
, Place_has_tag
, Article_has_tag
.
b) To samo dotyczy komentarzy.
c) czy utworzyć tablicę LikedPhotos [idUser, idPhoto]
, LikedArticles[idUser, idArticle]
, LikedPlace [idUser, idPlace]
. Liczba polubień będzie obliczana na podstawie zapytań (co, jak zakładam, jest złe). I...
Naprawdę nie podoba mi się ten projekt z ostatniej części, źle pachnie;)
2 II podejście :
Utworzę tabelę, w ElementType [idType, TypeName == some table name]
której administrator (ja) zapełni nazwy tabel, które można polubić , skomentować lub otagować . Następnie utworzę tabele :
a) LikedElement [idLike, idUser, idElementType, idLikedElement]
i to samo dla komentarzy i tagów z odpowiednimi kolumnami dla każdego. Teraz, gdy chcę zrobić zdjęcie polubione, wstawię:
typeId = SELECT id FROM ElementType WHERE TypeName == 'Photo'
INSERT (user id, typeId, photoId)
a dla miejsc:
typeId = SELECT id FROM ElementType WHERE TypeName == 'Place'
INSERT (user id, typeId, placeId)
i tak dalej ... Myślę, że drugie podejście jest lepsze, ale też czuję, że w tym projekcie też czegoś brakuje ...
Wreszcie zastanawiam się, gdzie najlepiej przechowywać licznik, ile razy ten element się podobał. Przychodzą mi do głowy tylko dwa sposoby:
- w
Photo/Article/Place
tabeli element ( ) - przez select count ().
Mam nadzieję, że moje wyjaśnienie tej kwestii jest teraz dokładniejsze.
Odpowiedzi:
Najbardziej rozszerzalnym rozwiązaniem jest posiadanie tylko jednej tabeli „bazowej” (połączonej z polubieniami, tagami i komentarzami) i „dziedziczenie” z niej wszystkich innych tabel. Dodanie nowego rodzaju encji polega po prostu na dodaniu nowej „odziedziczonej” tabeli - następnie automatycznie podłącza się ona do całej maszyny like / tag / comment.
Termin „związek encji” to „kategoria” (patrz Przewodnik po metodach ERwin , sekcja: „Relacje podtypów ”). Symbol kategorii to:
Zakładając, że użytkownik może polubić wiele encji, ten sam tag może być użyty dla więcej niż jednej encji, ale komentarz jest specyficzny dla encji, twój model mógłby wyglądać następująco:
A tak przy okazji, istnieją trzy sposoby na zaimplementowanie „kategorii ER”:
O ile nie masz bardzo rygorystycznych wymagań dotyczących wydajności, trzecie podejście jest prawdopodobnie najlepsze (co oznacza, że fizyczne tabele dopasowują 1: 1 jednostki na powyższym diagramie).
źródło
BIGINT
to 9223372036854775807. Zakładając, że wstawiasz jeden wiersz na sekundę, za ok. 300 miliardów lat skończą się dostępne wartości. Z pewnością do tego czasu będziesz w stanie przenosić na 128-bitowe liczby całkowite!Skoro „nienawidzisz” baz danych, dlaczego próbujesz je wdrożyć? Zamiast tego poproś o pomoc kogoś, kto kocha te rzeczy i je oddycha.
W przeciwnym razie naucz się kochać swoją bazę danych. Dobrze zaprojektowana baza danych upraszcza programowanie, projektowanie serwisu i usprawnia jego dalsze działanie. Nawet doświadczony projektant d / b nie będzie miał pełnego i doskonałego przewidywania: niektóre zmiany schematu będą potrzebne, gdy pojawią się wzorce użytkowania lub zmienią się wymagania.
Jeśli jest to projekt jednoosobowy, zaprogramuj interfejs bazy danych na proste operacje przy użyciu procedur składowanych: add_user, update_user, add_comment, add_like, upload_photo, list_comments, itd. Nie osadzaj schematu nawet w jednej linii kodu. W ten sposób schemat bazy danych można zmienić bez wpływu na kod: tylko procedury składowane powinny wiedzieć o schemacie.
Może być konieczne kilkakrotne refaktoryzowanie schematu. To normalne. Nie martw się, że za pierwszym razem zrobisz to idealnie. Po prostu spraw, by był wystarczająco funkcjonalny, aby prototypować początkowy projekt. Jeśli masz luksus czasu, użyj go trochę, a następnie usuń schemat i zrób to ponownie. Za drugim razem zawsze jest lepiej.
źródło
To jest ogólna idea. Nie zwracaj większej uwagi na stylizację nazw pól, a bardziej na relacje i strukturę
Ten pseudokod będzie zawierał wszystkie komentarze do zdjęcia o identyfikatorze 5
SELECT * FROM actions
WHERE actions.id_Stuff = 5
AND actions.typeStuff = "photo"
AND actions.typeAction = "comment"
Ten pseudokod otrzyma wszystkie polubienia lub użytkowników, którzy polubili zdjęcie o identyfikatorze 5
(możesz użyć count (), aby po prostu uzyskać liczbę polubień)
źródło
SELECT * FROM actions WHERE actions.id=133 AND actions.typeStuff = "comment" AND actions.typeAction = "like"
id_stuff
kolumna będzie zawierała unikalne wartości w każdej z trzech tabel?o ile rozumiem. wymaganych jest kilka tabel. Jest między nimi wiele do wielu relacji.
źródło
Spójrz na wzorce dostępu, których będziesz potrzebować. Czy któryś z nich wydaje się szczególnie utrudniać lub nieefektywny mój jeden lub drugi wybór dotyczący projektu?
Jeśli nie, faworyzuj tego, który wymaga mniejszej liczby stołów
W tym przypadku:
Myślę, że twoje „zróżnicowane” podejście, opcja 2, daje w niektórych przypadkach prostsze zapytania i nie wydaje się dużo gorsze w innych, więc wybiorę to.
źródło
Zdecydowanie wybierz drugie podejście, w którym masz jedną tabelę i przechowujesz typ elementu dla każdego wiersza, da ci to znacznie większą elastyczność. Zasadniczo, gdy logicznie można coś zrobić z mniejszą liczbą tabel, prawie zawsze lepiej jest mieć mniej tabel. Jedna zaleta, która przychodzi mi do głowy w tej chwili w twoim konkretnym przypadku, rozważ, że chcesz usunąć wszystkie polubione elementy określonego użytkownika, przy pierwszym podejściu musisz wysłać jedno zapytanie dla każdego typu elementu, ale przy drugim podejściu można to zrobić z tylko jednym zapytaniem lub rozważ, gdy chcesz dodać nowy typ elementu, przy pierwszym podejściu polega to na utworzeniu nowej tabeli dla każdego nowego typu, ale przy drugim podejściu nie powinieneś nic robić ...
źródło
Rozważ użycie tabeli na jednostkę dla komentarzy itp. Więcej tabel - lepsze dzielenie na fragmenty i skalowanie. Nie jest problemem kontrolowanie wielu podobnych tabel dla wszystkich znanych mi frameworków.
Pewnego dnia będziesz musiał zoptymalizować odczyty z takiej struktury. Możesz łatwo tworzyć tabele agragacyjne nad podstawowymi i trochę stracić na zapisach.
Jeden duży stół ze słownikiem może pewnego dnia stać się niekontrolowany.
źródło