MySQL: wiele tabel czy jedna tabela z wieloma kolumnami?

127

Więc to jest bardziej kwestia projektowa.

Mam jeden klucz podstawowy (powiedzmy identyfikator użytkownika) i mam mnóstwo informacji powiązanych z tym użytkownikiem.

Czy powinienem mieć wiele tabel podzielonych na kategorie zgodnie z informacjami, czy tylko jedną tabelę z wieloma kolumnami?

Sposób, w jaki to robiłem, polegał na tym, że miałem wiele tabel, na przykład jedna tabela na dane o użytkowaniu aplikacji, jedna tabela na informacje o profilu, jedna tabela na tokeny zaplecza itp., Aby wszystko wyglądało uporządkowane.

Niedawno ktoś mi powiedział, że lepiej tego nie robić w ten sposób, a tabela z dużą ilością kolumn jest w porządku. Chodzi o to, że wszystkie te kolumny mają ten sam klucz podstawowy.

Jestem całkiem nowy w projektowaniu baz danych, więc które podejście jest lepsze i jakie są wady i zalety?

Jaki jest konwencjonalny sposób na to?

Xavier_Ex
źródło
Dla jasności popraw mnie, jeśli się mylę, ale myślę, że „wiele tabel” można rozumieć jako link / tabelę asocjacyjną: en.wikipedia.org/wiki/Associative_entity
cellepo
1
Czy ta baza danych jest potrzebna do celów analitycznych lub przetwarzania operacyjnego / transakcyjnego?
Alexander Radev

Odpowiedzi:

113

Za każdym razem, gdy informacja jest jeden do jednego (każdy użytkownik ma jedną nazwę i hasło), prawdopodobnie lepiej jest mieć jedną tabelę, ponieważ zmniejsza to liczbę złączeń, które baza danych będzie musiała wykonać, aby pobrać wyniki. Myślę, że niektóre bazy danych mają ograniczenie liczby kolumn w tabeli, ale w normalnych przypadkach nie martwiłbym się tym i zawsze możesz podzielić to później, jeśli zajdzie taka potrzeba.

Jeśli dane są typu jeden do wielu (każdy użytkownik ma tysiące wierszy informacji o użytkowaniu), należy je podzielić na osobne tabele, aby zmniejszyć liczbę duplikatów danych (zduplikowane dane marnują przestrzeń dyskową, pamięć podręczną i sprawiają, że baza danych jest trudniejsza w utrzymaniu ).

Artykuł w Wikipedii dotyczący normalizacji baz danych może być interesujący, ponieważ szczegółowo omawia przyczyny takiego stanu rzeczy:

Normalizacja bazy danych to proces organizowania pól i tabel relacyjnej bazy danych w celu zminimalizowania nadmiarowości i zależności. Normalizacja zwykle polega na podzieleniu dużych tabel na mniejsze (i mniej nadmiarowe) tabele i zdefiniowaniu relacji między nimi. Celem jest wyodrębnienie danych, tak aby dodawanie, usuwanie i modyfikacje pola można było wprowadzać w jednej tabeli, a następnie propagować w pozostałej części bazy danych za pośrednictwem zdefiniowanych relacji.

Należy również pamiętać o denormalizacji , ponieważ są przypadki, w których powtarzanie danych jest lepsze (ponieważ zmniejsza ilość pracy, jaką musi wykonać baza danych podczas odczytu danych). Zdecydowanie zalecam, aby na początku Twoje dane były jak najbardziej znormalizowane i denormalizuj tylko wtedy, gdy masz świadomość problemów z wydajnością w określonych zapytaniach.

Brendan Long
źródło
Dziękuję za odpowiedź, więc po przeczytaniu wydaje mi się, że mówiłem o sytuacji informacyjnej jeden do jednego, gdy użytkownik ma wiele kolumn jeden do jednego.
Xavier_Ex
@Xavier_Ex - Tak, jeśli jest tylko jedna kolumna na użytkownika, to tylko jedna ogromna tabela użytkowników będzie łatwiejsza w obsłudze (i dużo łatwiejsza do optymalizacji silnika DB).
Brendan Long
Twój edytowany post zawiera więcej przydatnych informacji! Mam nowe obawy, że jeśli niektóre kolumny będą często aktualizowane, czy powinienem umieścić je w osobnych tabelach? Na przykład data urodzenia użytkownika nie będzie nigdy aktualizowana, ale token zaplecza może zostać unieważniony po pewnym czasie i będzie wymagał częstych aktualizacji. Czy byłoby lepiej, gdybym rozdzielił tabele w ten sposób, aby poprawić wydajność? Przeczytam teraz o wiki, o której wspomniałeś :)
Xavier_Ex
@Xavier_Ex - nie polecam tego. Znacznie lepszą wydajność uzyskuje się, gdy można wyszukać wszystkie potrzebne dane w jednej tabeli (zobacz artykuł dotyczący denormalizacji). Łączenia są drogie, ponieważ (1) wymagają wyszukiwania danych w wielu miejscach, co może wiązać się z wyszukiwaniem na obracającym się dysku, (2) zazwyczaj wymagają wielu indeksów i pewnego rodzaju scalania oraz (3) utrudniają planowanie zapytań, co nie zajmuje tylko czas, ale także zwiększa szanse, że optymalizator zapytań zrobi coś nie tak (a źle zoptymalizowane zapytania mogą być bardzo powolne).
Brendan Long
1
Ostatnio stanąłem przed tym samym problemem, ponieważ tabele MySQL InnoDB mają stosunkowo mały limit długości (~ 8000 bajtów). W mojej tabeli problemów (dane z bardzo długich formularzy ubezpieczeniowych, ponad 100 kolumn) mamy wiele kolumn varchar, wszystkie UTF8. Więc bez problemu wypełniliśmy limit ~ 8000 bajtów i cały czas otrzymywaliśmy „błąd 139 z silnika pamięci”. Musieliśmy więc podzielić stół. (Testowaliśmy z nowszym formatem Barracuda i działało bez dzielenia, ale serwery naszego klienta nadal używają MySQL 5.0).
MV.
12

Jeden duży stół to często kiepski wybór. Powiązane tabele to relacyjna baza danych, z którą została zaprojektowana. Jeśli indeksujesz poprawnie i wiesz, jak pisać wydajne zapytania, będą działać dobrze.

Gdy tabele zawierają zbyt wiele kolumn, mogą wystąpić problemy z rzeczywistym rozmiarem strony, na której baza danych przechowuje informacje. Albo rekord może okazać się zbyt duży dla strony, co może spowodować, że nie będziesz w stanie utworzyć lub zaktualizować określonego rekordu, co sprawia, że ​​użytkownicy są niezadowoleni, lub możesz (przynajmniej w SQL Server) zezwolić na pewne przepełnienie dla konkretnego typy danych (z zestawem reguł musisz sprawdzić, jeśli to robisz), ale jeśli wiele rekordów przekroczy rozmiar strony, możesz spowodować ogromne problemy z wydajnością. Teraz, jak MYSQL radzi sobie ze stronami i czy masz problem, gdy potencjalny rozmiar strony staje się zbyt duży, musisz sprawdzić w dokumentacji tej bazy danych.

HLGEM
źródło
1
Ach, różne głosy! Co jest zawsze świetne. Dziękuję za informację! Upewnię się, że jestem tego świadomy, kiedy robię swoje stoły ... ale nie wiedziałem, że początkowo będę musiał być świadomy rzeczy o tak niskim poziomie.
Xavier_Ex
4

Mam dobry przykład. Zbyt znormalizowana baza danych z następującym zestawem relacji:

people -> rel_p2staff -> staff

i

people -> rel_p2prosp -> prospects

Tam, gdzie ludzie mają imiona i dane o osobach, pracownicy mają tylko dane dotyczące rekordów personelu, potencjalni klienci mają tylko szczegóły dotyczące potencjalnych klientów, a tabele rel to tabele relacji z obcymi kluczami od osób łączących się z personelem i potencjalnymi klientami.

Ten rodzaj projektu dotyczy całej bazy danych.

Teraz, aby odpytać ten zestaw relacji, jest to łączenie wielotabelowe za każdym razem, czasami łączenie 8 i więcej tabel. Działało dobrze do połowy tego roku, kiedy zaczęło działać bardzo wolno teraz, gdy przekroczyliśmy 40000 rekordów ludzi.

Indeksowanie i wszystkie nisko wiszące owoce zostały zużyte w zeszłym roku, wszystkie zapytania są zoptymalizowane do perfekcji. To koniec drogi do konkretnego znormalizowanego projektu, a zarząd zatwierdził przebudowę całej aplikacji od niego zależnej, a także restrukturyzację bazy danych na okres 6 miesięcy. $$$$ Ouch.

Rozwiązaniem będzie mieć bezpośredni związek dla people -> staffipeople -> prospect

Vlad
źródło
Chciałbyś wiedzieć, jak poszła odbudowa? Czy w końcu zaprojektowałeś coś podobnego do dziedziczenia pojedynczego stołu, w którym miałeś typebyt a stafflub a prospect?
Coderama
1
Poszedłem z bezpośrednimi relacjami ludzie -> personel i ludzie -> potencjalny klient, działa czarująco, jest łatwy w użyciu, szybki do zapytań.
Vlad,
4

Przeszedł przez to i jako ktoś, kto często korzystał z MySQL, a następnie niedawno przeszedł na Postgres, jedną z największych zalet jest to, że możesz dodawać obiekty JSON do pola w Postgres.

Więc jeśli jesteś w tej sytuacji, nie musisz koniecznie decydować między jedną dużą tabelą z wieloma kolumnami i dzieleniem jej, ale możesz scalić kolumny w obiekty JSON, aby je zmniejszyć, np. Zamiast adresowania być 5 kolumnami, może po prostu być jednością. Możesz również zapytać o ten obiekt.

moinhaque
źródło
A co z wydajnością podczas używania obiektu json podczas zapytania?
dagalti
1
@dagalti wydajność jest dobra dla aplikacji, w których jej używałem. Nie wykonałem własnego testu porównawczego, ale może ci się to przydać
moinhaque
3

zadaj sobie te pytania, jeśli umieścisz wszystko w jednej tabeli, czy będziesz mieć wiele wierszy dla tego użytkownika? Jeśli musisz zaktualizować użytkownika, czy chcesz zachować ścieżkę audytu? Czy użytkownik może mieć więcej niż jedną instancję elementu danych? (na przykład numer telefonu) czy będziesz mieć przypadek, w którym mógłbyś chcieć później dodać element lub zestaw elementów? jeśli odpowiesz tak, najprawdopodobniej chcesz mieć tabele podrzędne z relacjami kluczy obcych.

Zalety tabel nadrzędnych / podrzędnych to integralność danych, wydajność za pomocą indeksów (tak, możesz to zrobić również na płaskiej tabeli) i łatwiejsze w utrzymaniu IMO, jeśli musisz później dodać pole, zwłaszcza jeśli będzie to pole wymagane.

Projektowanie wad jest trudniejsze, zapytania stają się nieco bardziej złożone

Ale jest wiele przypadków, w których jeden duży płaski stół będzie odpowiedni, więc aby podjąć decyzję, musisz spojrzeć na swoją sytuację.

Brian
źródło
Dziękuję za przypomnienie! Więc w moim przypadku rozważałem tylko przypadek, w którym każdy użytkownik nie może mieć więcej niż jednego wiersza, więc wszystkie pola informacyjne są jeden do jednego. Ponadto użytkownik nie może mieć więcej niż jednej instancji tego samego elementu, ponieważ uważam, że koncepcja jednego elementu nie może istnieć w więcej niż jednym miejscu. Jeśli chodzi o trzecie pytanie, tak, mogę dodać więcej elementów do tabeli, ale nie złamią one wymagań, o których wspomniałem powyżej. Myślę, że tabela nadrzędna / podrzędna jest dobra, gdy chcę powiązać wiele wierszy z jednym użytkownikiem, ale w tym przypadku obawiam się, że użytkownik ma wiele kolumn jeden do jednego.
Xavier_Ex
Nawet jeśli wszystkie elementy są obecnie jeden do jednego, nie eliminuje to potrzeby lub chęci posiadania tabel nadrzędnych / podrzędnych IMO. Prowadzenie dziennika zmienionych danych jest jednym z zastosowań. leniwe ładowanie obiektów to kolejna. chociaż są korzyści dla pojedynczej struktury tabeli, są też korzyści dla układów rodziców i dzieci (chociaż widziałem, jak ludzie idą do skrajności z nimi).
Brian
1

Skończyłem już projektować bazę danych. dla mnie zależy to od stopnia trudności systemu z zarządzaniem bazą danych; tak, to prawda, że ​​unikalne dane znajdują się tylko w jednym miejscu, ale naprawdę trudno jest tworzyć zapytania z nadmiernie znormalizowaną bazą danych z dużą ilością rekordów. Po prostu połącz oba schematy; użyj jednej ogromnej tabeli, jeśli czujesz, że będziesz mieć ogromne rekordy, które są trudne do utrzymania, tak jak Facebook, Gmail itp. i użyj innej tabeli dla jednego zestawu rekordów dla prostego systemu ... cóż, to tylko moja opinia .. mam nadzieję, że może to pomóc ... po prostu to zrób ... możesz to zrobić ... :)

Krzysztof
źródło
1
„użyj jednej ogromnej tabeli, jeśli będziesz mieć ogromne rekordy…” Ale Facebook, Google nie przechowuje danych użytkowników w jednej tabeli, rozdzielili je tyle samo tabel.
Yami Odymel,
0

Konwencjonalnym sposobem byłoby użycie różnych tabel, takich jak schemat gwiazdy lub schemat płatka śniegu. Jednak oparłbym tę strategię na podwójnej. Wierzę w teorię, że dane powinny istnieć tylko w jednym miejscu, tam schemat, o którym wspomniałem, działałby dobrze. Uważam jednak również, że w przypadku silników raportowania i pakietów BI podejście kolumnowe byłoby niezwykle korzystne, ponieważ jest bardziej zgodne z potrzebami raportowania. Podejścia kolumnowe, takie jak te z infobright.org, zapewniają ogromny wzrost wydajności i kompresję, co sprawia, że ​​użycie obu podejść jest niezwykle przydatne. Wiele firm zaczyna zdawać sobie sprawę, że tylko jedna architektura bazy danych w organizacji nie jest w stanie zaspokoić pełnego zakresu ich potrzeb. Wiele firm wdraża obie koncepcje posiadania więcej niż jednej architektury bazodanowej.

Craig Trombly
źródło
Dziękuję za informacje, ale przepraszam, że nie do końca rozumiem twoją odpowiedź ... Poszukam dwóch schematów, o których wspomniałeś jako pierwsze ...
Xavier_Ex
-4

Myślę, że posiadanie pojedynczej tabeli jest bardziej efektywne, ale powinieneś upewnić się, że tabela jest zorganizowana w sposób, który pokazuje związek, trend, a także różnicę w zmiennych w tym samym wierszu. na przykład, jeśli tabela pokazuje wiek i stopnie uczniów, należy ustawić tabelę w taki sposób, aby dzięki temu, że osoba uzyskująca najwyższy wynik była dobrze zróżnicowana, a różnica wieku uczniów była równa.

user8081853
źródło