Możliwość przeprojektowania bazy danych: Jakiego projektu tabeli użyć do gromadzenia danych z czujników?

13

tło

Mam sieć około 2000 czujników, z których każdy ma około 100 punktów danych, które zbieramy co 10 minut. Te punkty danych są zwykle wartościami całkowitymi, ale niektóre są łańcuchami i liczbami zmiennoprzecinkowymi. Te dane powinny być przechowywane przez 90 dni, więcej, jeśli to możliwe i nadal wydajne.

Projektowanie bazy danych

Kiedy pierwotnie zlecono mu ten projekt, napisałem aplikację C #, która napisała pliki oddzielone przecinkami dla każdego czujnika. W tamtym czasie nie było ich tak wiele, gdy ktoś chciał przyjrzeć się trendom, otworzyliśmy plik CSV w programie Excel i zobrazowaliśmy go w razie potrzeby.

Sprawy rosły i przeszliśmy na bazę danych MySQL. Stworzyłem tabelę dla każdego czujnika (tak, wiem, wiele tabel!); działał dobrze, ale ma pewne ograniczenia. Przy tak wielu tabelach oczywiście niemożliwe jest napisanie zapytania, które znajdzie dane wśród wszystkich czujników, gdy szuka się określonej wartości.

W następnej wersji przełączyłem się na Microsoft SQL Server Express i umieściłem wszystkie dane czujnika w jednej dużej tabeli. Działa to również i pozwala nam wyszukiwać wartości wśród wszystkich interesujących czujników. Jednak natrafiłem na limit 10 GB dla wersji Express i zdecydowałem się wrócić do MySQL zamiast inwestować w SQL Server Standard.

Pytanie

Jestem zadowolony z wydajności i skalowalności MySQL, ale nie jestem pewien, czy najlepiej zastosować podejście oparte na danych w jednym stole. 10 GB w jednym stole wydaje się wymagać innego projektu. Powinienem wspomnieć, że nadal istnieje potrzeba zapytania danych o wykresy i obawiam się, że pojawią się problemy z wydajnością zapytania, które przedstawia wykresy, na przykład dane dotyczące temperatury dla jednego czujnika przez pełne 90 dni. (Innymi słowy, wykres powinien być czymś, co można szybko wytworzyć, bez czekania, aż SQL posortuje stosy danych w celu odizolowania sensora).

Czy powinienem w jakiś sposób podzielić tę tabelę, aby zwiększyć wydajność? Czy to nie jest niezwykłe mieć tak duży stół?

Mam indeksy w kolumnach Identyfikator czujnika i Znacznik czasu, co stanowi w zasadzie granice definiujące każde zapytanie. (tzn. uzyskaj dane dla czujnika X od czasu A do czasu B).

Przeczytałem trochę o dzieleniu i dzieleniu na partycje, ale nie sądzę, aby były one odpowiednie w tym przypadku.


Edytować:

Na podstawie dotychczasowych komentarzy i odpowiedzi przydatne mogą być dodatkowe informacje:

Nieokreślony czas przechowywania: obecnie nie przechowuję danych z ostatnich 90 dni. Codziennie uruchamiam zapytanie, które usuwa dane starsze niż 90 dni. Jeśli stanie się to ważne w przyszłości, zgromadzę więcej, ale na razie wystarczy. Pomaga to utrzymać rozmiar pod kontrolą i wysoką (er) wydajność.

Typ silnika: Oryginalna implementacja MySQL używała MyISAM. Tym razem podczas tworzenia tabel dla nowej implementacji (jedna tabela danych zamiast wielu) domyślnie wybrano InnoDB. Nie wydaje mi się, żebym wymagał jednego lub drugiego.

Normalizacja: Istnieją oczywiście inne tabele oprócz tabeli gromadzenia danych. Te tabele wsparcia przechowują takie informacje, jak informacje o sieci dla czujników, dane logowania dla użytkowników itp. Nie ma wiele do normalizacji (o ile mi wiadomo). Tabela danych ma tak wiele kolumn, ponieważ istnieje tyle zmiennych z każdego czujnika. (Wiele temperatur, poziomów światła, ciśnienia powietrza itp.) Normalizacja według mnie oznacza, że ​​nie ma zbędnych danych ani powtarzających się grup. (Przynajmniej dla 1NF.) Dla danego czujnika przechowywanie wszystkich wartości w określonym czasie wymaga jednego wiersza danych i nie ma w tym związku żadnych relacji 1: N (które widzę).

Mógłbym funkcjonalnie rozdzielić tabelę, tworząc (na przykład) wszystkie wartości związane z temperaturą w jednej tabeli, a wszystkie wartości związane z ciśnieniem powietrza w innej. Chociaż może to poprawić wydajność osoby wykonującej zapytanie tylko z temperaturą, nadal muszę wstawić wszystkie dane naraz. Mimo to wzrost wydajności może być opłacalny dla operacji SELECT. Oczywiście lepiej byłoby podzielić tabelę w pionie na podstawie tego, jak często użytkownicy żądają danych. Być może to wszystko, co powinienem zrobić. Wydaje mi się, że zadając moje pytanie, szukam potwierdzenia, że ​​warto byłoby to zrobić.


Edycja 2:

Wykorzystanie danych: Ostatecznie większość danych nigdy nie jest przeglądana ani potrzebna, ponieważ zazwyczaj koncentrujemy się tylko na elementach z problemami. Ale próbując znaleźć problemy, używamy różnych narzędzi do wyszukiwania danych i określania, które elementy należy powiększyć.

Zauważyliśmy na przykład korelację między wartością użycia pamięci (zastrzeżonego oprogramowania klienta) a ponownym uruchomieniem / awarią. Jeden z punktów danych, który zbieram, odnosi się do tego użycia pamięci i mogłem spojrzeć na dane historyczne, aby pokazać, że urządzenia stają się niestabilne po przekroczeniu określonego użycia pamięci. Dzisiaj dla podzbioru urządzeń z tym oprogramowaniem sprawdzam tę wartość i wydaje polecenie ponownego uruchomienia, jeśli jest ona zbyt wysoka. Dopóki tego nie odkryłem, nie sądziłem, że zbieranie tych danych będzie miało wartość.

Z tego powodu utrzymywałem, że około 100 punktów danych jest gromadzonych i przechowywanych, nawet jeśli wartość jest wątpliwa. Ale w normalnym codziennym użytkowaniu użytkownicy zwykle sprawdzają może kilkanaście tych parametrów. Jeśli użytkownik zainteresuje się określonym obszarem geograficznym, może (przy użyciu oprogramowania) generować wykresy lub arkusze danych dla kilkudziesięciu czujników. Nierzadko patrzy się na 30-dniowy wykres z dwiema lub trzema liniami wykresu pokazującymi takie rzeczy, jak temperatura, ciśnienie powietrza i poziomy światła. W ten sposób uruchomione zostanie zapytanie podobne do tego:

SELECT sensor_id, location, data_timestamp, temp1, air1, light1
FROM data
WHERE data_timestamp >= '2012-02-01'
AND sensor_id IN (1, 2, 3);

(W oryginalnej wersji MySQL, w której każdy czujnik miał własną tabelę, wydawane byłyby trzy osobne zapytania, ale wyniki były łączone w oprogramowanie do utworzenia wykresu.)

Ponieważ datatabela zawiera tak wiele wierszy (~ 10 milionów), pomimo włączonych wskaźników idi data_timestamp, wydajność jest wyraźnie gorsza niż scenariusz z wieloma tabelami (4500 wierszy zwróconych w ciągu 9 sekund w przeciwieństwie do mniej niż jednej sekundy w tym przykładzie). Możliwość znalezienia czujników spełniających określone kryteria jest praktycznie zerowa w schemacie wielostołowym, a zatem powodem przejścia do pojedynczego stołu.

Ten typ zapytania może być wykonywany przez wielu użytkowników w krótkich odstępach czasu, gdy wybierają oni różne grupy danych i porównują wykresy z każdego wyniku. Czasem frustracja może być odczekanie prawie 10 sekund na wykres lub arkusz kalkulacyjny.

Dane są odrzucane po 90 dniach. Można go zarchiwizować, ale obecnie nie jest to wymagane.

Mamy nadzieję, że te informacje pomogą bardziej odpowiednio pokazać, w jaki sposób dane są wykorzystywane po ich gromadzeniu i przechowywaniu.

JYelton
źródło
Aby na to pytanie uzyskać właściwą odpowiedź, prawdopodobnie powinieneś rozwinąć sposób, w jaki dane są faktycznie wykorzystywane. Wyprzedzasz informacje na temat głębokości informacji, które podałeś do tej pory, ale możesz zadawać pytanie pod niewłaściwym kątem.
Mark Storey-Smith
Dobra uwaga, @Mark, rozwinę to również. Starałem się nie zadawać zbyt długiego pytania z obawy, że to przytłoczy.
JYelton

Odpowiedzi:

5

Powinieneś pomyśleć o podzieleniu tabeli z ważnego powodu.

Wszystkie indeksy, które masz na gigantycznej tabeli, nawet tylko jeden indeks, mogą generować duże obciążenie procesora i dyskowe operacje wejścia / wyjścia tylko po to, aby wykonać konserwację indeksu podczas wykonywania operacji INSERT, UPDATE i DELETE.

Wcześniejszy post, 7 października 2011 r., Napisałem o tym , dlaczego podział tabel byłby wielką pomocą. Oto jeden fragment mojego poprzedniego postu:

Partycjonowanie danych powinno służyć do grupowania danych logicznie i spójnie w tej samej klasie. Wydajność przeszukiwania każdej partycji nie musi być głównym czynnikiem, o ile dane są poprawnie pogrupowane. Po osiągnięciu partycjonowania logicznego skoncentruj się na czasie wyszukiwania. Jeśli tylko oddzielasz dane tylko według identyfikatora, możliwe jest, że dostęp do wielu wierszy danych nie będzie możliwy w celu odczytu lub zapisu. To powinno być najważniejsze: zlokalizuj wszystkie identyfikatory, do których najczęściej uzyskiwany jest dostęp, i podziel według partycji. Wszystkie rzadziej używane identyfikatory powinny znajdować się w jednej dużej tabeli archiwum, która jest nadal dostępna podczas wyszukiwania indeksu dla zapytania „raz w błękitne księżyc”.

Później możesz przeczytać cały mój post .

Aby przejść do sedna, musisz poszukać i dowiedzieć się, jakie dane są rzadko używane w tabeli 10 GB. Dane te należy umieścić w tabeli archiwum, która jest łatwo dostępna, jeśli potrzebujesz zapytań adhoc o charakterze historycznym. Migracja tego archiwum z 10 GB, a następnie OPTIMIZE TABLEtabeli 10 GB, może spowodować, że zestaw roboczy będzie szybciej uruchamiał SELECT, INSERT, UPDATE i DELETE. Nawet DDL działałby szybciej na zestawie roboczym 2 GB niż na stole 10 GB.

AKTUALIZACJA 2012-02-24 16:19 EDT

Dwie kwestie do rozważenia

  1. Z twojego komentarza wynika, że ​​normalizacja jest tym, czego możesz potrzebować.
  2. Być może trzeba będzie przeprowadzić migrację wszystkiego, co ma ponad 90 dni do tabeli archiwum, ale jednocześnie uzyskać dostęp do archiwum i zestawu roboczego w tym samym czasie. Jeśli wszystkie Twoje dane to MyISAM, zalecamy użycie silnika pamięci masowej MERGE. Najpierw tworzysz mapę tabeli MERGE, która jednoczy zestaw roboczy tabeli MyISAM i tabelę archiwum MyISAM. Przechowujesz dane w mniej niż 91 dniach w jednej tabeli MyISAM i przenosisz do archiwum wszelkie dane z 90 dni. Zapytałbyś tylko o mapę tabeli MERGE.

Oto dwa posty, które napisałem o tym, jak go używać:

Oto dodatkowy post, który napisałem na tabelach z dużą ilością kolumn

Zbyt wiele kolumn w MySQL

RolandoMySQLDBA
źródło
Są kolumny, które są rzadziej potrzebne, ale wszystkie czujniki otrzymują mniej więcej taki sam procent uwagi. Dlatego mogę sobie wyobrazić podzielenie tabeli w pionie byłoby korzystne. Na przykład 20-kolumnowa tabela (często dostępna) i 80-kolumnowa tabela (rzadko dostępna). Nie jestem pewien, czy to jest to samo, co partycjonowanie.
JYelton
Dzięki za edycję. Przeczytałem twój post o „Zbyt wielu kolumnach w MySQL”. Zmodyfikuję moje pytanie, dodając kilka dodatkowych punktów, które mogą być przydatne.
JYelton
5

Interesujące ... Jeśli wszystkie czujniki generują ten sam rodzaj danych, sensowne jest umieszczenie ich wszystkich w tej samej tabeli, ale przy takiej ilości danych widzę, dlaczego martwisz się o wydajność.

Czy 90 dni to zazwyczaj czas, przez który tworzony jest wykres? Jeśli tak, możesz mieć dwie tabele: główną tabelę danych czujnika, która przechowuje dane z 90 (lub nieco więcej, jeśli chcesz mieć luz) dni temu do dziś, i wszystko starsze niż to idzie w tabeli archiwum. Może to pomóc zmniejszyć rozmiar tabeli, z której generowane są raporty, i mam nadzieję, że większość 10 GB danych będzie w tabeli archiwum, a nie w głównej tabeli. Zadanie archiwizacji można zaplanować na nocne uruchamianie.

Być może rozważ także zbudowanie oddzielnej bazy danych raportowania, która przechowuje dane w strukturze, która jest lepsza do generowania raportów (tabele zaprojektowane w celu ściślejszego dopasowania do zapytań, i może wstępnie obliczyć i agregować wartości, które w innym przypadku zajęłyby dużo czasu generuj, jeśli to możliwe) i wypełniaj je ponownie z głównej bazy danych regularnie (np. co noc). Oczywiście, jeśli potrzebujesz raportów generowanych na podstawie aktualnych danych, może to nie działać tak dobrze.

FrustratedWithFormsDesigner
źródło
Przechowywanie czegokolwiek z ostatnich 90 dni w tym momencie nie jest konieczne, ale byłoby fajne. Zgadzam się, że najlepiej przechowywać w tabeli „archiwum”. Wykresy i analiza danych wahają się od zaledwie godzin do pełnych 90 dni. Większość żądań graficznych wykorzystuje tylko dane z ostatniego tygodnia, ale wykresy 90-dniowe są powszechne. Nasza firma (jeszcze) nie zażądała dłuższych raportów.
JYelton
@JYelton: Możesz mieć tyle poziomów w tym podejściu, ile chcesz. Najbardziej aktualny stół może mieć tylko od dzisiaj. Następny stół może mieć od dziś do 2 tygodni temu. Następny stół może mieć od dziś do 90 dni temu. Ostatni stół może WSZYSTKO.
FrustratedWithFormsDesigner
Jeśli dobrze cię rozumiem, mówisz o powtórzeniu tabeli, ale z różnymi okresami. Więc jeśli ktoś poprosi o raport z 7 dni, wykorzystana zostanie tabela, która cofnie się tylko o tydzień. Jeśli następnie zwiększą się do 8 dni, zostanie wykorzystany następny największy stół (np. 30-dniowy)? Z pewnością poprawiłoby to szybkość zapytań o krótszym czasie trwania, ale kosztem przechowywania (taniego) i logiki programowania do radzenia sobie z tabelami warstwowymi (nie tak tanimi).
JYelton
@JYelton: Tak, myślę, że rozumiesz to poprawnie. Jeśli przedziały czasowe zapytań są standardowe (dziś - 1 dzień, dziś - 7 dni, dziś - 30 dni, dziś - 90 dni), nie sądzę, że będzie to zbyt trudne, ponieważ zawsze będziesz wiedział, do której tabeli trafienie. Jeśli przedziały czasowe mogą mieć różną długość, przy czym początkiem zakresu może nie być bieżąca data, to logika do wdrożenia będzie trudna, a zapytania, które krzyżowanie tabel mogą kosztować przy operacjach UNION na wielu tabelach.
FrustratedWithFormsDesigner