2009-11-05 14 views
11

Używam SQL Server do przechowywania danych historycznych szeregów czasowych dla kilkuset tysięcy obiektów, obserwowanych około 100 razy dziennie. Zauważyłem, że zapytania (daj mi wszystkie wartości dla obiektu XYZ między czasem t1 a czasem t2) są zbyt wolne (dla moich potrzeb, powolność jest większa niż sekunda). Indeksuję według znacznika czasu i identyfikatora obiektu.składnica klucz-wartość dla danych szeregów czasowych?

Rozumiem, że zamiast tego używam czegoś w rodzaju sklepu z kluczem, takiego jak MongoDB, ale nie jestem pewien, czy jest to "odpowiednie" użycie tego typu rzeczy, i nie mogłem znaleźć żadnych wzmianek wykorzystania takiej bazy danych dla danych szeregów czasowych. idealnie, byłbym w stanie wykonać następujące zapytania:

  • pobrać wszystkie dane dla obiektu XYZ między t1 i t2 czas
  • wykonaj wyżej, ale zwraca jeden punkt datę dziennie (pierwszy i ostatni zamknięte do czasu t ...)
  • odzyskać wszystkie dane dla wszystkich obiektów dla określonego znacznika czasu

dane powinny być zamówione, a najlepiej powinna być szybko pisać nowych danych oraz aktualizacji istniejących danych .

Wygląda na to, że moje pragnienie zapytania za pomocą identyfikatora obiektu oraz znacznika czasu może wymagać posiadania dwóch kopii bazy danych indeksowanych na różne sposoby w celu uzyskania optymalnej wydajności ... każdy ma doświadczenie w budowaniu takiego systemu, z klucz-wartość magazynu lub HDF5, czy coś innego? czy jest to całkowicie wykonalne w SQL Server i po prostu nie robię tego dobrze?

+0

Bummer, że nikt nie odpowiedział na to pytanie ... Pytam to jeszcze raz, żeby sprawdzić, czy ktoś coś wie. – btelles

Odpowiedz

3

Wygląda na to, że MongoDB byłby bardzo dobry. Aktualizacje i wkładki są bardzo szybko, więc może chcesz utworzyć dokument dla każdego zdarzenia, takie jak:

{ 
    object: XYZ, 
    ts : new Date() 
} 

Następnie można indeksu pole ts i zapytania będą również szybko. (Nawiasem mówiąc, można utworzyć wiele indeksów na jednej bazie danych).

Jak zrobić swoje trzy pytania:

pobrać wszystkie dane dla obiektu XYZ między t1 i czas t2

db.data.find({object : XYZ, ts : {$gt : t1, $lt : t2}}) 

zrobić powyżej, ale powróci jedna data punkt dziennie (pierwsza, ostatnia, zamknięte czasu t ...)

// first 
db.data.find({object : XYZ, ts : {$gt : new Date(/* start of day */)}}).sort({ts : 1}).limit(1) 
// last 
db.data.find({object : XYZ, ts : {$lt : new Date(/* end of day */)}}).sort({ts : -1}).limit(1) 

Dla najbliżej pewnego czasu, to prawdopodobnie trzeba niestandardowej funkcji JavaScript, ale jest to wykonalne.

odzyskać wszystkie dane dla wszystkich obiektów na konkretny znacznik czasu

db.data.find({ts : timestamp}) 

krępuj się zapytać na user list jeśli masz jakiekolwiek pytania, ktoś inny może być w stanie myśleć o łatwiejszy sposób uzyskiwanie zdarzeń zbliżonych do czasu.

+5

Nie jestem pewien, czy pracowałeś z szeregiem czasowym w przeszłości, ale ten rodzaj projektu NIE jest skalowany. –

+2

@Matthieu N (lub ktokolwiek inny) zależy na opracowaniu? –

2

Dlatego istnieją bazy danych specyficzne dla danych szeregów czasowych - relacyjne bazy danych po prostu nie są wystarczająco szybkie dla dużych serii czasowych.

W bankach inwestycyjnych często używam Fame. Jest bardzo szybki, ale wyobrażam sobie, że jest bardzo drogi. Jeśli jednak twoja aplikacja wymaga prędkości, warto ją obejrzeć.

1

Niedawno wypróbowałem coś podobnego w F #. Zacząłem od 1-minutowego formatu pręta dla danego symbolu w pliku rozdzielanym spacjami, który ma około 80 000 minut 1-minutowych odczytów. Kod do załadowania i przeanalizowania z dysku trwał poniżej 1 ms. Kod obliczający 100-minutowy wskaźnik SMA dla każdego okresu w pliku wynosił 530 ms. Mogę wyciągnąć dowolny kawałek, który chcę z sekwencji SMA po przeliczeniu na mniej niż 1ms. Uczę się tylko F #, więc prawdopodobnie istnieją sposoby na optymalizację. Zauważ, że było to po wielu testach, więc było już w pamięci podręcznej Windows, ale nawet po załadowaniu z dysku nigdy nie dodaje więcej niż 15 ms do obciążenia.

data, godzina, otwarte, wysokie, niskie, gęste, objętość 03/01/2011,08: 00: 00,94.38,94.38,93.66,93.66,3800

Aby skrócić czas przeliczania zapisać cała obliczona sekwencja wskaźników na dysk w pojedynczym pliku z \ n ogranicznikiem i na ogół zajmuje mniej niż 0,5ms, aby załadować i przeanalizować, gdy znajduje się w pamięci podręcznej plików systemu Windows. Prosta iteracja w pełnych zestawach danych czasowych w celu zwrócenia zestawu rekordów w zakresie dat w operacji sub 3ms z pełnymi rocznymi słupkami o długości 1 minuty. Przechowuję także dzienne paski w osobnym pliku, który ładuje się jeszcze szybciej z powodu niższych wolumenów danych.

Używam warstwy .net4 System.Runtime.Caching do buforowania zserializowanej reprezentacji wstępnie obliczonej serii, a dzięki kilku pamięciom RAM przeznaczonym dla pamięci podręcznej uzyskuję prawie 100% trafień w pamięci podręcznej, więc mój dostęp do Wstępnie wyliczony zestaw wskaźników dla dowolnego symbolu generalnie trwa poniżej 1 ms.

Ciągnięcie dowolnego fragmentu danych, które chcę ze wskaźnika, zwykle trwa mniej niż 1 ms, więc zaawansowane zapytania po prostu nie mają sensu. Korzystając z tej strategii, mogłem z łatwością załadować 10 lat paska 1 minuty w czasie krótszym niż 20 ms.

// Parse a \n delimited file into RAM then 
// then split each line on space to into a 
// array of tokens. Return the entire array 
// as string[][] 
let readSpaceDelimFile fname = 
    System.IO.File.ReadAllLines(fname) 
    |> Array.map (fun line -> line.Split [|' '|]) 

// Based on a two dimensional array 
// pull out a single column for bar 
// close and convert every value 
// for every row to a float 
// and return the array of floats. 
let GetArrClose(tarr : string[][]) = 
    [| for aLine in tarr do 
     //printfn "aLine=%A" aLine 
     let closep = float(aLine.[5]) 
     yield closep 
    |] 
2

Istnieje baza danych czasu wolnego typu open source w ramach aktywnego rozwoju (na razie tylko platforma .NET), którą napisałem. Może przechowywać ogromne ilości (terrabajów) jednolitych danych w stylu "binarnego płaskiego pliku". Wszystkie zastosowania są ukierunkowane strumieniowo (do przodu lub do tyłu). Aktywnie wykorzystujemy go do przechowywania i analizy kleszczy w naszej firmie.

Nie jestem pewien, czy będzie to dokładnie to, czego potrzebujesz, ale pozwoli ci uzyskać pierwsze dwa punkty - uzyskaj wartości od t1 do t2 dla dowolnej serii (jedna seria na plik) lub po prostu weź jeden punkt danych.

https://code.google.com/p/timeseriesdb/

// Create a new file for MyStruct data. 
// Use BinCompressedFile<,> for compressed storage of deltas 
using (var file = new BinSeriesFile<UtcDateTime, MyStruct>("data.bts")) 
{ 
    file.UniqueIndexes = true; // enforces index uniqueness 
    file.InitializeNewFile(); // create file and write header 
    file.AppendData(data); // append data (stream of ArraySegment<>) 
} 

// Read needed data. 
using (var file = (IEnumerableFeed<UtcDateTime, MyStrut>) BinaryFile.Open("data.bts", false)) 
{ 
    // Enumerate one item at a time maxitum 10 items starting at 2011-1-1 
    // (can also get one segment at a time with StreamSegments) 
    foreach (var val in file.Stream(new UtcDateTime(2011,1,1), maxItemCount = 10) 
     Console.WriteLine(val); 
} 
+0

Nie wiem, dlaczego nikt inny nie przegłosował, ale spóźnił się, dziękując za udostępnienie – MrMesees

0

używam hdf5 jako mojego repozytorium szeregów czasowych. Ma wiele efektywnych i szybkich stylów kompresji, które można łączyć i dopasowywać. Może być używany z wieloma różnymi językami programowania.

Używam boost :: date_time dla pola sygnatury czasowej.

W sferze finansowej, następnie tworzę określone struktury danych dla każdego z barów, tyknięć, transakcji, ofert, ...

Stworzyłem kilka niestandardowych iteratorów i wykorzystałem standardowe funkcje biblioteki szablonów, aby móc efektywnie wyszukiwać określone wartości lub zakresy rekordów opartych na czasie.

Powiązane problemy