2012-11-13 16 views
5

Moi użytkownicy mogą aktualizować swoje informacje, które są zapisywane w określonej liczbie kolumn w tabeli, na przykład: user (id INT, email VARCHAR, phone VARCHAR, address VARCHAR).Który układ danych użytkownika plus dziennik zmian jest najbardziej wydajny i zajmuje mniej miejsca?

Widziałem inne implementacje, takie jak ta dla Wordpress, które przechowuje te informacje dla użytkowników w tabeli o nazwie usermeta z układem (umeta_id INT, user_id INT, meta_key VARCHAR, meta_value VARCHAR).

W dzienniku zmian, który chcę zaimplementować, oceniam między używaniem takiego rozwiązania lub tworzenia (co myślę, że będzie lepsze), układem takim jak: userLog (id INT, date TIMESTAMP, email VARCHAR, phone VARCHAR, address VARCHAR).
Tak, mogę mieć historię wszystkich informacji, które każdy użytkownik miał w danym dniu. Wiersze rejestrowałyby tylko zmiany, mając NULL na niezmienionych kolumnach.

Na pierwsze pytanie: Czy jest jakaś korzyść z tego rodzaju układ inny niż jest w stanie stworzyć nowy typ informacji tylko przez wstawienie odpowiedniego meta_key?
Czasami myślę, że ten układ może nie być odpowiedni, jeśli wydajność jest sprawą w moim środowisku, ponieważ korzystałbym z VARCHAR dla każdego rodzaju danych, które chcę przechowywać.

Na drugie pytanie: Czy przechowywanie i wydajność wybierania/wstawiania rzeczywiście mają znaczenie dla obu rozwiązań, które rozważam?
Które rozwiązanie powinno być mniej (lub więcej) zajmujące przestrzeń i/lub mniej (lub więcej) wybrać/wstawić bardziej wydajnie niż inne i dlaczego?

+0

Jakiego systemu baz danych używasz? – sufleR

+0

@sufleR MySQL i PostgreSQL. – Mario

Odpowiedz

3

Niektóre myśli, jeśli niekoniecznie odpowiedź:

Wyraźnie dziennik zmian jest must-have dla ciebie, więc oryginalna konstrukcja z pojedynczym rzędzie dla każdego użytkownika nie jest rozwiązaniem dla Ciebie. Więc mówimy o wyborze pomiędzy:

  1. Pojedynczy wiersz dla każdej wersji zestawu danych każdego użytkownika; lub
  2. Pojedynczy wiersz za wersją item każdego użytkownika informacji

Rozwiązanie 1 odpowiada Twoim

userLog (id INT, date TIMESTAMP, email VARCHAR, phone VARCHAR, address VARCHAR) 

Rozwiązanie 2 odpowiada Wordpress jednym:

umeta_id INT, user_id INT, meta_key VARCHAR, meta_value VARCHAR 

Twoje pytanie 1: Nie widzę żadnej korzyści dla rozwiązania 2, z wyjątkiem tego, jeśli później zdecydujesz, że chcesz o przechwyć użytkowników (na przykład) URL witryny lub (na przykład) ulubiony kolor, możesz to zrobić, dodając meta_key. Ale równie łatwo można to zrobić w ramach rozwiązania 1, wykonując po prostu czynność To nie jest trudne. Chyba że DBA w twoim sklepie są wyjątkowo dobermannowe (;)). Ponieważ przechowujesz dziennik zmian, wszyscy istniejący użytkownicy (w momencie zmiany) będą teraz mieli pustą kolumnę WebsiteURL; ale to jest dokładnie to, czego potrzebujesz: nie znasz ich adresu URL, ponieważ system nie przechwycił go wcześniej. Oczywiście, nowa kolumna będzie musiała być NIESTABILNA - ale i tak może być nieunikniona, nawet z "początkowymi" danymi, chyba że metoda, której używasz do przechwytywania informacji o użytkownikach, nalega na e-mail, telefon i adres jako wymagane kolumny.

Dla mnie wady rozwiązania meta_key przewyższają zalety. Wadami są:

  • Trzeba rozwijać kawałek kodu przegubu do obracania informacji o użytkowniku dla jednego użytkownika na jednym
    rzędu. Musisz wywoływać ten kod w każdym miejscu, w którym chcesz uzyskać informacje o użytkowniku w jednym wierszu. W Natomiast Porada1 wymaga jedynie

    SELECT USERID [wszystkie Informacja o użytkowniku] Z userLog INNER JOIN (SELECT MAX (USERID datechanged) AS LatestDAteChanged OD userlog GROUP BY identyfikator użytkownika) A na userlog.userid = a.userID I userlog .DateChanged = a.LatestDAteChanged

    , która jest znacznie wydajniejsza niż oś obrotu. Z indeksem na UserID, DateChanged, to będzie działać jak wiatr.

  • Jeśli naprawdę nie chcesz przechowywać wartości meta_key wiele razy w tabeli informacji o użytkowniku (e-mail, e-mail, e-mail, e-mail, e-mail), potrzebna jest dodatkowa tabela Meta_Key_Lookup.

Drugie pytanie: Dla ostatecznego czasoprzestrzeni wydajności, tak, meta_key Solution2 jest najlepszy. Zwłaszcza, jeśli nie używasz metakeys VARCHAR, ale wartości metakey ID i masz osobną tablicę meta_key lookup (np. 1 = Email, 2 = Telefon itd.). Ale nie sądzę, że jest to rozstrzygający argument dla meta_key Solution2, biorąc pod uwagę praktycznie zerową cenę pamięci i trudności związane z tym rozwiązaniem.

(Uwaga/zamysł: IMHO Twój pomysł na zachowanie wartości NULL w twoim rozwiązaniu1, gdzie wartość się nie zmieniła, to zła droga. Kodowanie, aby spróbować uzyskać najnowszą wiadomość e-mail, następnie telefon, a następnie adres (osobno) dla każdego użytkownika, będzie koszmarem: prawie tak trudnym do zakodowania/przetestowania - i do uruchomienia serwera - jako osią obrotową wymaganą przez inne rozwiązanie, a zmniejszenie pamięci marginalnej. Wystarczy przytrzymać cały rząd za każdym razem, gdy Jeśli nie podasz przykładów, a prawdziwy zestaw informacji o użytkowniku ma 50 kolumn szerokości ...)

IMHO problem z pamięcią masową nie jest decydujący. Przejdźmy zatem do wydajności SELECT/INSERT:

W tej kwestii myślę, że rozwiązanie 1 nadal wygrywa. Na wkładkach wygrywa 1 wygrana: wstawiany jest tylko jeden wiersz, nawet jeśli użytkownik zmienia każde pole w swoich informacjach. W SELECTS, SOlution 1 wygrywa ponownie: potrzebujesz tylko widoku najnowszych informacji na użytkownika (powyższy kod), z czym jest zoptymalizowany SQL. Natomiast rozwiązanie 2 wymagałoby przestawienia: coś, co SQL nie jest dobre.

+0

Właściwie wstawię, a raczej aktualizuję, w jednym wierszu dla każdego użytkownika. Dziennik zmian zawierający wartości NULL zostanie zapełniony przez wyzwalacze. Myślę, że to najlepsze podejście, jakie mogę teraz myśleć. Podobny do tego, co powiedziałeś w poprzednim akapicie. – Mario

+0

Zaletą rozwiązania ogólnego (meta_key) jest to, że pozwala on przechowywać dziennik zmian wielu tabel (z dodatkowym kluczem tabeli lub kluczem kolumny unikalnym dla wszystkich tabel). –

+0

Hej, @sebt, na wypadek gdybyś był zainteresowany ... Zrobiłem test z dwiema tabelami z rzędem na użytkownika. Jeden trzyma cały zestaw danych każdego użytkownika, a drugi ma tylko zmienione dane i NULL dla pozostałych komórek. Wstawiono około trzech milionów losowych zmian dla różnych użytkowników w obu tabelach i porównano ich rozmiar na dysku twardym. Zgadnij co, oba były dokładnie takie same ... naprawdę ciekawe, może Postgres robi już jakąś optymalizację dla tego rodzaju przypadków. Cóż, proszę bardzo. : P – Mario

1

Zgadzam się z @sebt na temat standardowych rozwiązań SQL.

Jeśli potrzebujesz elastycznego rozwiązania w PostgreSQL, polecam Ci typ hstore (postgresql 9.1 docs). Ten typ może przechowywać wiele kluczy => par wartości w jednej kolumnie.
Istnieje wiele możliwych sposobów wstawiania, wyszukiwania i indeksowania tej kolumny. Dokumentacja to dobry sposób na rozpoczęcie poszukiwań.

1

Najlepszy wybór zależy w dużej mierze od tego, co chcesz zrobić, a więc od tego, jakie pytania będziesz musiał przeprowadzić (jak w przypadku wielu rzeczy).

Nie bardzo rozumiem WordPressa (dostaję fakt, że przechowujesz poszczególne pola jako wiersze, ale nie wiem, gdzie one pasują), więc po prostu wymienię wszystkie opcje:

  1. nas użytkownika i historii tabele przechowywania pojedynczych pól w rzędzie
  2. mieć tylko historia sklep stół poszczególne pola w rzędzie
  3. mieć tylko sklep stół użytkownik poszczególnych pól w rzędzie
  4. mają ani przechowywać poszczególne pola w rzędzie
  5. Have 1 połączony stół zarówno dla użytkownika i historii
  6. mieć 1 połączoną tabelę dla obu przechowywania poszczególnych pól w rzędzie

(5) i (6) tak naprawdę nie wydaje się opcji w większości przypadków, jak Podejrzewam, że chcesz uzyskać szczegółowe informacje dla użytkownika (lub grupy użytkowników) częściej niż chciałbyś uzyskać historię (chyba, że ​​większość twoich zapytań ma uzyskać obie w tym samym czasie).

(1) i (3) nie są zalecane, chyba że wiele szczegółów nie zostanie wypełnionych (dlatego w innych przypadkach otrzymasz bardzo rzadkie tabele).

(4) jest dla użytkowników, którzy mają tendencję do zmiany wszystkich swoich szczegółów na raz, co prawdopodobnie nie zdarza się często, podejrzewam, że ludzie po prostu zmieniają 1 lub 2 pola na raz. Tak więc (2) jest prawdopodobnie lepszą opcją, zwłaszcza jeśli tabela użytkownika zawiera wiele pól (a ludzie zmieniają tylko 1 lub 2 pola naraz).

Ogólnie rzecz biorąc, przechowywanie poszczególnych pól w rzędzie oznacza zmniejszoną przestrzeń do przechowywania powyżej wydajności (zakładając, że są puste pola, w przeciwnym razie przechowywanie poszczególnych pól w każdym wierszu jest gorsze), w zasadzie określa się, które z nich jest najlepsze, patrząc na swoje wymagania i spodziewane dane. Pamiętajmy, że mówimy głównie o selekcji tutaj, która jest ogólnie powolną operacją, chyba że masz jakieś dziwne rzeczy, albo mnóstwo insertów na raz. Dla historii, zmniejszone przechowywanie jest na ogół preferowane powyżej wydajności, więc (2).

Dodanie pól jest w dużej mierze pewnym wysiłkiem, więc samo powiedzenie "AKTUALIZUJ użytkownika ADD COLUMN col" nie jest tak naprawdę wielką sprawą, może nawet zostać zautomatyzowane. Byłby to kolejny (mały) powód do preferowania (2) powyżej (4).

Powiązane problemy