Struktura bazy danych - jedna duża tabela czy wiele małych

0

Cześć, próbuje znaleźć odpowiedź na pytanie jak powinna wyglądać struktura prostej bazy danych.

Założenia
Baza będzie przechowywać dane projektów, zleceń przypisanych do danego projektu, oraz użytkowników z przypisanymi zleceniami, czyli coś w stylu prostego task managera z podziałem na projekty.

Mój obecny pomysł na strukturę tabel

Projekty

CREATE TABLE projects (
    project_id INT AUTO_INCREMENT PRIMARY KEY,
    project_name VARCHAR(255) NOT NULL,
    /* reszta kolumn dla projektów */
);

Użytkownicy

CREATE TABLE users (
    user_id INT AUTO_INCREMENT PRIMARY KEY,
    user_name VARCHAR(255) NOT NULL,
    user_lastname VARCHAR(255) NOT NULL
    /* reszta kolumn dla użytkowników */
);

Zlecenia

CREATE TABLE tasks (
    task_id INT AUTO_INCREMENT PRIMARY KEY,
    task_project_id INT NOT NULL
    task_assigned_by_id INT NOT NULL
    task_assigned_to_id INT NOT NULL
    /* reszta kolumn dla zlecenia */
    FOREIGN KEY (task_project_id) REFERENCES projects(project_id)
    FOREIGN KEY (task_assigned_by_id) REFERENCES users(user_id)
    FOREIGN KEY (task_assigned_to_id) REFERENCES users(user_id)
);

Powyższa struktura działa tak jak powinna, ale co jeżeli projektów będzie 100, gdzie do każdego projektu będzie przypisane powiedzmy 1000 zleceń? Jeżeli dobrze rozumiem, to z każdym nowym projektem przykładowo pobieranie wszystkich zleceń z danego projektu będzie coraz bardziej obciążać bazę. Czy nie byłoby zatem lepiej tworzyć nową tabelę ze zleceniami dla każdego projektu?

Zlecenia

CREATE TABLE tasks_{id_projektu} (
    task_id INT AUTO_INCREMENT PRIMARY KEY,
    task_assigned_by_id INT NOT NULL
    task_assigned_to_id INT NOT NULL
    /* reszta kolumn dla zlecenia */
    FOREIGN KEY (task_assigned_by_id) REFERENCES users(user_id)
    FOREIGN KEY (task_assigned_to_id) REFERENCES users(user_id)
);

Nie znalazłem jednoznacznej odpowiedzi na to pytanie stąd też mój post. Z góry dziękuję za każdą odpowiedź.

6
grb123 napisał(a):

Powyższa struktura działa tak jak powinna, ale co jeżeli projektów będzie 100, gdzie do każdego projektu będzie przypisane powiedzmy 1000 zleceń? Jeżeli dobrze rozumiem, to z każdym nowym projektem przykładowo pobieranie wszystkich zleceń z danego projektu będzie coraz bardziej obciążać bazę. Czy nie byłoby zatem lepiej tworzyć nową tabelę ze zleceniami dla każdego projektu?

Mniemanie wydajnościowe jest zupełnie błędne.
I BARDZO szkodliwe pod względem użyteczności.
Zarówno 100, jak i 1000 to jest jak w wojsku pół litra na dwóch, czyli nic. Byle indeksy były.
Co więcej, Twój pomysł mógłby POGARSZAĆ wydajność zależnie od kontekstu

Tak na marginesie, tutaj słowa "duża tabela" rozumiemy chyba częściej jako tabela bardzo szeroka, prawie zawsze się to bierze ze złego projektu.
Nazwy 255 znaków bym raczej rozbił na kilka mniejszych kolumn O DOBRZE OKREŚLONEJ zawartości (typ i nazwa). Mam przeczucie, ze chcesz w tych mega-polach kombinować jak koń pod górę. Krótsze, sensownie nazwane i w niektórych przypadkach indeksowane.

A jakiego języka programowania chcesz to obsługiwać?

4

Obczaj postacie normalne (1, 2, 3), o co mniej więcej chodzi: https://www.sqlpedia.pl/projektowanie-i-normalizacja-bazy-danych
Wydaje mi się, że podchodząc do planowania bazy ze zdrowym rozsądkiem idziemy w kierunku 2/3NF. Ale też nie jest tak, że zawsze trzeba się tego kurczowo trzymać.

0
AnyKtokolwiek napisał(a):
grb123 napisał(a):

Powyższa struktura działa tak jak powinna, ale co jeżeli projektów będzie 100, gdzie do każdego projektu będzie przypisane powiedzmy 1000 zleceń? Jeżeli dobrze rozumiem, to z każdym nowym projektem przykładowo pobieranie wszystkich zleceń z danego projektu będzie coraz bardziej obciążać bazę. Czy nie byłoby zatem lepiej tworzyć nową tabelę ze zleceniami dla każdego projektu?

Mniemanie wydajnościowe jest zupełnie błędne.
I BARDZO szkodliwe pod względem użyteczności.
Zarówno 100, jak i 1000 to jest jak w wojsku pół litra na dwóch, czyli nic. Byle indeksy były.
Co więcej, Twój pomysł mógłby POGARSZAĆ wydajność zależnie od kontekstu

Tak na marginesie, tutaj słowa "duża tabela" rozumiemy chyba częściej jako tabela bardzo szeroka, prawie zawsze się to bierze ze złego projektu.
Nazwy 255 znaków bym raczej rozbił na kilka mniejszych kolumn O DOBRZE OKREŚLONEJ zawartości (typ i nazwa). Mam przeczucie, ze chcesz w tych mega-polach kombinować jak koń pod górę. Krótsze, sensownie nazwane i w niektórych przypadkach indeksowane.

A jakiego języka programowania chcesz to obsługiwać?

Będę używać MySQL i PHP,

3

Powyższa struktura działa tak jak powinna, ale co jeżeli projektów będzie 100, gdzie do każdego projektu będzie przypisane powiedzmy 1000 zleceń? Jeżeli dobrze rozumiem, to z każdym nowym projektem przykładowo pobieranie wszystkich zleceń z danego projektu będzie coraz bardziej obciążać bazę.

A jak czesto będziesz wyciągać wszystkie 1000 zleceń? Bez prawdziwych danych często jest to wróżenie z fusów. Chociaż jak wyżej napisano 100 * 1000 to jeszcze nie jest duzo danych

Czy nie byłoby zatem lepiej tworzyć nową tabelę ze zleceniami dla każdego projektu?

Dobra baza danych potrafi robic to z automatu za Ciebie. Nazywa die to partycjonowanie tabeli. Partycjonowanie na pewno jest w PostgreSQLu i brzydkiej bazie na O. Nie wiem jak w innych

1
grb123 napisał(a):

Czy nie byłoby zatem lepiej tworzyć nową tabelę ze zleceniami dla każdego projektu?

Zlecenia

CREATE TABLE tasks_{id_projektu} (
    task_id INT AUTO_INCREMENT PRIMARY KEY,
    task_assigned_by_id INT NOT NULL
    task_assigned_to_id INT NOT NULL
    /* reszta kolumn dla zlecenia */
    FOREIGN KEY (task_assigned_by_id) REFERENCES users(user_id)
    FOREIGN KEY (task_assigned_to_id) REFERENCES users(user_id)
);

Nie znalazłem jednoznacznej odpowiedzi na to pytanie stąd też mój post. Z góry dziękuję za każdą odpowiedź.

Jeśli ktoś ma takie pytanie, to oznacza, że odpowiedź na nie jest zazwyczaj przecząca. ZAWSZE jak widzę (no może poza jakimiś bardzo specyficznymi wymaganiami które w tej chwili nie przychodzą mi do głowy) oddzielne tabele generowane z programu dla nowych np projektów jak u Ciebie to zapala mi się czerwona lampka. Zwłaszcza, że piszesz o wydajności nie sprawdzając tego. Ja zazwyczaj stosuję takie podejście. Tworzę odpowiednie tabele bez wnikania w wydajność. Dopiero jak mi wydajność zaczyna siadać, to myślę co by tu poprawić w strukturze danych. Chociaż parę razy zdarzyło mi się sprawdzić to jak będą się zachowywać zapytania uzupełniając tabele losowymi danymi. Jednak nigdy to nie było przy takiej liczbie rekordów jak u Ciebie. Przy 100k rekordach musiałbyś naprawdę coś popsuć (albo struktura bazy albo zapytania) ewentualnie uruchamiać to na 20 letnim komputerze aby były znaczące problemy wydajnościowe.

Pomyśl jeszcze tak. A co będzie jeśli będziesz zechciał zrobić zestawienie z wszystkich projektów? Będziesz z poziomu klienta iterować po wszystkich 1000 tabel, wysyłał zapytanie do bazy, zapamiętywał wyniki i ręcznie łączył aby coś pokazać na ekranie? Przecież to będzie masakrycznie wolne. Zamiast jednego zapytania na tabeli z większą liczbą rekordów wydasz 1000 oddzielnych zapytań do małych tabel. Chyba nie muszę mówić co będzie szybsze.

0

To co chcesz zrobic to "sharding", ale raczej robi sie to na poziomie serwerow baz danych a nie tabel.
I glownie po to zeby rozdzielic dane ze wzgledow bezpieczenstwa, ew. jak masz miliard uzytkownikow.

Poki co, nie wiem czy bylo juz wspomniane, ale poczytaj o indeksach.

1 użytkowników online, w tym zalogowanych: 0, gości: 1