Temat dość prosty.
Tabela `measurements` z 98% kolumnami numerycznymi. Aktualnie ~33 kolumn.
Problem. Jak to przechowywać. Aktualnie zrobiłem PoC żeby działało. Teraz jak już działa to mogę się zająć optymalizacją.
Szukam jakiegoś sensownego rozwiązania...
1. Zostawić tak jak jest
+ czytelność
+ łatwość dodawania nowej kolumny
- szybko puchnie w szerz
2. Trzymanie w JSON
+ optymalizacja miejsca
- problem z dodaniem nowej kolumny
3. Zserializowany obiekt
+ łatwe trzymanie
- problem z dodaniem nowej kolumny
Biorę po 100zł z konta każdej drużyn i słucham Państwa...
Takie poziome spuchnięte tabele to po prostu zły design, a jak numeryczne to już w ogóle kicha. Nie mam pojęcia co to jest PoC, ale dlaczego nie możesz po prostu dodawać tych cech jako rekordów?
Proof of Concept
To też rozważałem... I jest to kolejny pomysł.
Ja wiem że pakowanie w szerz to nie jest najlepszy pomysł dla tego słcuam głosu ludu
A i kolejna uwaga to taka że zawsze będę pobierał wszytstkie wartości dla każdego wiersza.
Nie będę przeszukiwał/sortował/filtrował po tych parametrach. Kluczowych będzie tylko 3-4 reszta jako wartości pomiarowe per cecha.
Ja bym zostawił jak jest. Zaczniesz normalizować i Ci wydajnościowo klęknie. Użyjesz JSONa i sie wyłożysz gdy będzie trzeba coś w nim znaleźć lub zmodyfikować.
> Ja wiem że pakowanie w szerz to nie jest najlepszy pomysł dla tego słcuam głosu ludu
Ale dlaczego? Jeżeli to są sensowne, różnorodne dane, co to jest w tym złego? Co to są dokładnie za dane? Trzymanie tego w formie jakieś zserializowanej tablicy, JSON-a itp. będzie najprawdopodobniej dużo mniej optymalne pod względem szybkości działania, objętości zajmowanego miejsca na dyskach/w pamięci, nie mówiąc już o jakimkolwiek wyszukiwaniu/filtrowaniu danych.
Tak jak pisałęm są to dane numeryczne int, decimal.
Nie będzie wyszukiwania po tych danych, filtrowania ani innych operacji.
Zawsze pobierane są wszystkie te dane bo generowany jest z nich PDF i dodatkowo widok tabelaryczny.
Dla tego zastanawiałem się nad ew. optymalizacją ale jak pisałem problem potem może być w modyfikacji struktury tych danych tj, np. dodanie kolejnych kolumn.
Stąd pytanie czy ktoś ma jakiś fajny pomysł na to. Nie chcę dostawiać kolejnych potworków typu mongo czy elastic czy kij wie jeszcze bo za mało tego będzie na armaty. Rozwiązanie ma być proste z założenia
Spokojnie, ja jestem z tych którzy piszą rozwiązanie w miaarę optymalne i nie bawią się w mikrooptymalizacje jeśli ich nie potrzeba.
Odpowiadając...
> Jeżeli każda z tych ~30 wartości reprezentuje coś innego, coś unikalnego, coś co nie jest jakąś grupą/kolekcją/agregatem danych to każda z nich powinna być osobnym bytem - w przypadku bazy danych: kolumną.
To są dane pomiarowe ciała człowieka, tj. obwody, składy masy ciała, tłuszczu itd. Dane są zbierane z wagi mierzącej skład ciała.
> Nie potrzebujesz wykonywać takich operacji teraz do osiągnięcia wymaganego efektu, ale nie zdziw się jak za 5 miesięcy, ktoś Cię poprosi o wycinek danych z marca, albo o ten raport za jakieś 5000 czy 6000 czegoś tam i najszybszym wykonaniem tego nowego zadania będzie napisanie prostej SQL-ki.
Jesli ktoś poprosi o wycinek danych to i tak muszą być pobrane wszystkie dane bo one są integralne i są robione obliczenia już później.
Co do jeszcze samej optymalizacji to chyba raczej o proces developmentu. Obecne rozwiązanie nie jest złe, jednak biorąc np. pod uwagę jak by wyglądało Entity w SF dla takiej tabeli to mnie głowa boli
Doctrine'owska encja faktycznie będzie miała wtedy 30 właściwości i niech je sobie ma, skoro ona ma na dobrą sprawę odzwierciedlać to co jest w bazie danych. Jeżeli część z tych danych można jakoś sensownie zgrupować też to możesz zrobić przy pomocy @Embeeded. Przecież encję i tak wykorzystuje się tylko na poziomie/w warstwie aplikacji przy bezpośredniej komunikacji ze źródłem danych, także zbyt często z tym potworkiem do czynienia mieć nie będziesz.
Innymi słowy - mając 30 różnych danych (a wszystko wskazuje na to, że masz) musisz prędzej czy później się z nimi w kodzie spotkać i zdecydowanie lepiej mieć każdą z nich jawnie i klarownie zdefiniowaną.
Myślałem jeszcze nad takim rozwiązaniem żeby wepchać je wszystkie w JSON do BD a potem zrobić mappera na to który będzie przez jakąś magiczną metodę pobierał wartości. więc w kodzie dalej będę mógł operować na pojedynczych wartościach.
Dodatkow w mapperze ustawić domyślną strukturę i przy pobieraniu zrobić merge, więc będę miał zawsze oczekiwaną strukturę nawet jeśli w BD będzie stara, a przy zapisie tylko wyjdzie update.
Zerknę jeszcze w Embedded bo może to mi trochę pomoże bo w sumie mogę zrobić kilka grup bo jest tam np. masa mięśni całkowita + 5 wartości z rozbiciem. Wtedy to ma sens.
Ja to zrozumiałem tak, że masz kolumny typu cośtam1, cośtam2, cośtam3. Gdyby tak było, wtedy byłby duży problem chociażby z wyszukiwaniem.
Jeśli to wszystko są faktycznie cechy ściśle związane z encją, to 30 kolumn będzie w porządku, chociaż wydaje mi się, że taka sytuacja jest rzadka. Przeważnie coś jednak stanowi osobną encję i jest np. wykorzystywane przez wiele innych rekordów.
Może się podziel strukturą tej tabeli?
A na zdrowie
CREATE TABLE `measurements` ( `id` int(10) UNSIGNED NOT NULL, `user_id` int(10) UNSIGNED NOT NULL, `m_c` smallint(5) UNSIGNED DEFAULT NULL, `m_ub` smallint(5) UNSIGNED DEFAULT NULL, `m_ar` smallint(5) UNSIGNED DEFAULT NULL, `m_al` smallint(5) UNSIGNED DEFAULT NULL, `m_w` smallint(5) UNSIGNED DEFAULT NULL, `m_t` smallint(5) UNSIGNED DEFAULT NULL, `m_h` smallint(5) UNSIGNED DEFAULT NULL, `m_thr` smallint(5) UNSIGNED DEFAULT NULL, `m_thl` smallint(5) UNSIGNED DEFAULT NULL, `m_car` smallint(5) UNSIGNED DEFAULT NULL, `m_cal` smallint(5) UNSIGNED DEFAULT NULL, `weight` decimal(5,1) UNSIGNED DEFAULT NULL, `height` tinyint(3) UNSIGNED DEFAULT NULL, `al` tinyint(3) UNSIGNED DEFAULT NULL, `fw` double(6,1) DEFAULT NULL, `far` double(6,1) DEFAULT NULL, `fal` double(6,1) DEFAULT NULL, `ffr` double(6,1) DEFAULT NULL, `frf` double(6,1) DEFAULT NULL, `ft` double(6,1) DEFAULT NULL, `mw` double(6,1) DEFAULT NULL, `mar` double(6,1) DEFAULT NULL, `mal` double(6,1) DEFAULT NULL, `mfr` double(6,1) DEFAULT NULL, `mfl` double(6,1) DEFAULT NULL, `mt` double(6,1) DEFAULT NULL, `bw` double(6,1) DEFAULT NULL, `if` tinyint(3) UNSIGNED DEFAULT NULL, `rd` smallint(5) UNSIGNED DEFAULT NULL, `ra` tinyint(3) UNSIGNED DEFAULT NULL, `ww` double(6,1) DEFAULT NULL, `measurement_date` date NOT NULL, `created_at` timestamp NULL DEFAULT NULL, `updated_at` timestamp NULL DEFAULT NULL, `expected_weight` tinyint(3) UNSIGNED DEFAULT NULL, `activity_level` tinyint(3) UNSIGNED NOT NULL DEFAULT '1' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
Wepchasz to w JSON-a: będzie wolniejsze pod każdym względem: czasu zapisu, odczytu, modyfikacji, miejsca na dysku, czasu odczytu/zapisu przez PHP-a, wprowadzania zmian (będziesz musiał jak sam zaznaczyłeś pisać jakieś magiczne mappery/mergery) czyli ogólnie rzecz biorąc: dewelopmentu. Po co to wszystko? Jeżeli masz zasób, który składa się z relatywnie dużej liczby właściwości... no OK, z reguły jest to oznaka czegoś złego, ale tutaj nie wydaje się tu być przypadkiem. Tylko zlituj się sam nad sobą i stosuj pełne nazwy dla kolumn - to nie lata 80 by długość tego typu nazw miała dla czegoś znaczenie.
Moja poprzednia sugestia z cechami jako rekordami może nie jest tutaj najlepsza, bo zestaw cech jest chyba stały. Albo względnie pełny pomiar, albo wcale.
Ale pomyślałem sobie o czymś. Czy użytkownik pojawia się w bazie zawsze z pomiarami? Pewnie nie, bo kolumny są nullable. Dlatego rozważyłbym wstawienie pomiarów do osobnej tabeli, z relacją 1:1 z użytkownikiem. Kosztem tego będzie oczywiście konieczność JOIN-owania, które jednak dla wydajności nie ma praktycznie żadnego znaczenia, ale już do pisania zapytań ma. Jest jednak kilka zalet takiego rozwiązania:
Może jednak iść w stronę normalizacji? Zrób sobie słownik parametrów:
id, nazwa (m_c, m_ub itd)
i tabelę dla parametrów pomiarów:
id_pomiaru, id_parametru, wartość
Minus taki, że kolumna wartość musiałaby posiadać „wspólny” typ danych czyli u Ciebie pewnie decimal(6,1). Nie wiem jak zapisujesz dane do bazy ale kluczem głównym słownika pomiarów wcale nie musi być sztuczna wartość 1, 2, 3... a właśnie m_c, m_ub (wówczas w polu nazwa masz słowną nazwę parametru). Może właśnie to będzie najlepszym rozwiązaniem?
Pomiarów jest więcej i dałeś po jednej kolumnie per jednostka pomiaru? Dziwne rozwiązanie.
Czy te pomiary są zupełnie niezależne od siebie? Tzn. czy może być pomiar jednej rzeczy bez innej rzeczy? I czy są jakieś grupy pomiarów, czyli np. dwie cechy (lub więcej) zawsze będą razem mierzone, nigdy osobno?
Pytanie do mnie
@phpion to też jest jakieś rozwiązanie, nie uzależniam się od ilości parametrów, ale właśnie wspólny typ który jak zauważyłeś mógłby być DECIMAL(6,1)
@Smoku
Z tych danych można wyodrębnić 2 grupy po 6 cech i one zawsze będą razem bo to maszynowy pomiar całkowity + rozbicie.
I co masz na mysli mówiąc:
>> Pomiarów jest więcej i dałeś po jednej kolumnie per jednostka pomiaru? Dziwne rozwiązanie.
Wybacz, nie doczytałem. Myślałem, że przechowujesz te pomiary w tabli `users`. W takim razie może rozdzielić te tabele na zestawy pomiarów?
Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)