Uruchamiamy aplikację internetową z obsługą bazy danych do analizy danych, obecnie oparte na C#.NET z EntityFramework na serwerze i w zasadzie z фреймворками HTML+Javascript po stronie klienta (na podstawie Internetu).
Nasza aplikacja regularnie otrzymuje dane pomiarowe X/Y w dużych ilościach, tj. 1e6 lub więcej, przesłane przez użytkowników lub uzyskane w inny infrastrukturą.
Obecnie mamy tabela w MSSQL pod nazwą Values
z id, series_id as int; x, y, z as float
. Tabela ta stanowi BULK INSERT
jest wypełniany, gdy klient pobiera je, i odpowiednie metadane są zapisywane w Series
stół. Całkowity rozmiar BAZY danych w obecnie zbliża się do 1 TB, 99,99% z nich wynosi Values
dane.
To podejście było proste w realizacji, ale ma kilka wad, które z czasem zrobili jego skomplikowane i powolne:
- musimy wklejać fragmenty, aby nie przeciążać proces IIS, który go wstępnie przetwarza (obecnie 200 000 punktów danych na fragment).
- Wymagania co do pamięci procesu IIS podczas WSTAWIANIA są ogromne (>1500 MB do 200 MB danych).
- wstaw dzieje się zbyt wolno (5 milionów rekordów stanowią 100 MB, wstaw zajmuje >30 sekund nawet przy użyciu MASOWEGO WSTAWIANIA).
- podczas WSTAWIANIA cała tabela jest zablokowana, czyli jednocześnie może wstawić tylko jeden użytkownik
- pobieranie danych odbywa się również dość powoli, żądanie rekordów 1e6 czasami zajmuje >10 sekund
- usuwanie serii z rekordami >1e6 regularnie prowadzi do limitu аутам na stronie internetowej aplikacji.
Dane nigdy nie są wybierane częściowo, dlatego nas tak naprawdę nie potrzebują, aby były one w tabeli. ALE on jest "obniżona" do wyświetlania przed wysyłką do klientów, Czyli nagrywania 1e6 domyślnie, czyli w 99% przypadków użycia, zmniejszone do 2000 lub 10 000 rekordów przed wysłaniem do klienta. Ten zestaw jest buforowana na kliencie, ale jeśli nowy klient prosi o ten sam zestaw, z którym przetwarzane ponownie. W tabeli wartości także indeks na series_id
który zajmuje więcej miejsca na dysku niż sama tabela.
Zastanawiam się czy ma sens zmienić ten format przechowywania do magazynu obiektów blob w "Wartościach" z własnym formatem danych (CSV lub JSON lub plik binarny) i ewentualnie dodatkowymi kolumnami z wstępnie obrobionymi "obniżonymi" zestawami danych do wyświetlania, które można wysyłać klientom bez zmian (na przykład w formacie JSON). Tak, że nowy Values
format tabeli będzie mniej więcej tak
id, series_id, data(blob), reduced_data(blob)
i był tylko jeden Value
w Series
wpis, a nie 1e6 lub więcej. Obniżony zestaw danych zostanie utworzony jeden raz przy odbiorze pobranych danych, a następnie wykorzystywane do wyświetlania na życzenie klienta
Stracę częściową kontrolę nad values
według identyfikatora lub wartości X/Y, ale wartości nigdy nie są wybierane na podstawie czegokolwiek, z wyjątkiem id
lub series_id
tak, że w dzisiejszych czasach to nie jest ograniczeniem. Oto moje pytania:
- Czy ma to w ogóle sens? Spodziewam się, że tworzenie i usuwanie dużego zestawu danych BLOB zawsze będzie znacznie szybciej, niż tworzenie i usuwanie 1 000 000 rekordów. Prawda?
- Binary blob lub CSV/JSON/.. KROPLA? Najprostszy podejście do przechowywania dużych obiektów binarnych, oczywiście, polega na tym, aby stworzyć ogromny fragment CSV lub JSON i zapisz go (być może, w postaci skompresowanej) w bazie danych. Niestandardowy format binarny danych byłby jeszcze mniej, ale trzeba go było przekształcić w JSON przed wysyłką do klientów.
Mam wrażenie, że dodatkowe problemy, związane z binarnymi formatami danych, mogą tego nie kosztować, i lepiej skompresować duży obiekt binarny CSV/JSON, niż wymyślać format binarny. Prawda?
Jak o innych wad, plam, o których, być może, nawet nie wiem? Ograniczenia rozmiaru, jak się wydaje, nie są problemem, varbinary(MAX)
to wystarczy. Nie potrzebuję wskaźnik do wartości wewnątrz dużego obiektu binarnego, tylko dla metadanych (które znajdują się w tabeli rzędów).
Myśli?