Хранилище ключей для данных временных рядов?

Я использую SQL Server для хранения исторических данных временных рядов за пару сотен тысяч объектов, наблюдаемых около 100 раз в день. Я нахожу, что запросы (дайте мне все значения для объекта XYZ между временем t1 и временем t2) слишком медленны (для моих нужд медленнее больше секунды). Я индексирую по метке времени и объекту.

Я размышлял над тем, что вместо этого использовал somethings хранилище для ключей, например MongoDB, но я не уверен, что это "подходящее" использование такого рода вещей, и я не мог найти никаких упоминаний о используя такую ​​базу данных для данных временных рядов. В идеале я мог бы выполнить следующие запросы:

  • получить все данные для объекта XYZ между временем t1 и временем t2
  • выполните вышеуказанные действия, но верните одну точку в день (сначала, последний, закрытый до времени t...)
  • получить все данные для всех объектов для определенной отметки времени

данные должны быть заказаны, и в идеале он должен быть быстрым для записи новых данных, а также для обновления существующих данных.

похоже, что мое желание запросить идентификатор объекта, а также временную метку может потребовать, чтобы две копии базы данных индексировались по-разному, чтобы получить оптимальную производительность... у кого-нибудь есть опыт создания такой системы, с ключом -value store, или HDF5, или что-то еще? или это полностью выполнимо в SQL Server, и я просто не делаю это правильно?

Ответ 1

Похоже, что MongoDB будет очень хорошим. Обновления и вставки очень быстрые, поэтому вы можете создать документ для каждого события, например:

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

Затем вы можете проиндексировать поле ts, и запросы также будут быстрыми. (Кстати, вы можете создавать несколько индексов в одной базе данных.)

Как выполнить ваши три запроса:

получить все данные для объекта XYZ между временем t1 и временем t2

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

выполните вышеуказанное, но верните одну дату точка в день (первая, последняя, ​​закрытая до время 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)

В течение ближайшего времени вам, вероятно, потребуется специальная функция JavaScript, но это возможно.

получить все данные для всех объектов для конкретная временная метка

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

Не стесняйтесь спрашивать в список пользователей, если у вас есть какие-либо вопросы, кто-то может подумать о более легком способе получения события, близкие к событиям.

Ответ 2

Вот почему существуют базы данных, специфичные для данных временных рядов - реляционные базы данных просто недостаточно быстры для больших временных рядов.

Я использовал Fame довольно много в инвестиционных банках. Это очень быстро, но я думаю, что это очень дорого. Однако, если ваше приложение требует скорости, возможно, стоит посмотреть его.

Ответ 3

Существует база данных с открытым исходным кодом для активной разработки (только для .NET), которую я написал. Он может хранить массивные суммы (террабайты) однородных данных в "двоичном плоском файле". Все использование ориентировано на потоки (вперед или назад). Мы активно используем его для хранения и анализа складских тиков в нашей компании.

Я не уверен, что это будет именно то, что вам нужно, но это позволит вам получить первые две точки - получить значения от t1 до t2 для любых серий (по одной серии для каждого файла) или просто взять одну точку данных.

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);
}

Ответ 4

Недавно я попробовал что-то подобное в F #. Я начал с формата строки в 1 минуту для соответствующего символа в файле с разделителем пространства, который имеет примерно 80 000 минут в минуту. Код для загрузки и разбора с диска был меньше 1 мс. Код для вычисления 100-минутного SMA за каждый период в файле составил 530 мс. Я могу вытащить любой фрагмент, который я хочу из последовательности SMA, как только вы подсчитали менее 1 мс. Я просто изучаю F #, поэтому есть способы оптимизации. Обратите внимание, что это было после нескольких тестовых прогонов, поэтому оно уже было в кэше Windows, но даже при загрузке с диска он никогда не добавляет к нагрузке более 15 мс.

дата, время, открытый, высокий, низкий, близко, объем 01/03/2011,08: 00: 00,94.38,94.38,93.66,93.66,3800

Чтобы сократить время пересчета, я сохраняю всю вычисленную последовательность индикаторов на диск в одном файле с разделителем \n и обычно занимает менее 0,5 мс для загрузки и анализа, когда в кеше файлов Windows. Простая итерация по всем данным временного ряда, чтобы вернуть набор записей в диапазоне дат в течение 3 мс с полным годом в 1 минуту баров. Я также сохраняю ежедневные бары в отдельном файле, который загружается еще быстрее из-за более низких объемов данных.

Я использую слой .net4 System.Runtime.Caching для кэширования сериализованного представления предварительно вычисленной серии и с паровым гигабайтом ОЗУ, выделенным для кеша, я получаю почти 100% -ный коэффициент попадания в кеш, поэтому мой доступ к любому предикату - установленный набор индикаторов для любого символа обычно работает под 1 мс.

Вытягивание любого фрагмента данных, который требуется от индикатора, обычно меньше 1 мс, поэтому расширенные запросы просто не имеют смысла. Используя эту стратегию, я мог бы легко загрузить 10-летнюю шкалу за 1 минуту менее чем за 20 мс.

// 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
    |]

Ответ 5

Я использую HDF5 как репозиторий временных рядов. Он имеет ряд эффективных и быстрых стилей сжатия, которые можно смешивать и сопоставлять. Он может использоваться с несколькими языками программирования.

Я использую boost:: date_time для поля timestamp.

В финансовой сфере я создаю конкретные структуры данных для каждого из баров, тиков, сделок, котировок,...

Я создал ряд пользовательских итераторов и использовал стандартные функции библиотеки шаблонов, чтобы иметь возможность эффективно искать конкретные значения или диапазоны записей, основанных на времени.