Как хранить 7,3 миллиарда строк рыночных данных (оптимизированных для чтения)?


86

У меня есть набор данных за 1 минуту по 1000 акций с 1998 года, всего около (2012-1998)*(365*24*60)*1000 = 7.3 Billion строк.

В большинстве случаев (99,9%) я буду выполнять только чтение запросы на .

Как лучше всего хранить эти данные в БД?

  • 1 большая таблица с 7,3 млрд строк?
  • 1000 таблиц (по одной для каждого символа акций) с 7,3 млн строк в каждой?
  • какие-либо рекомендации по движку базы данных? (Я планирую использовать MySQL Amazon RDS)

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

Редактировать:

Это образец строки:

'XX', 20041208, 938, 43.7444, 43.7541, 43.735, 43.7444, 35116.7, 1, 0, 0

Столбец 1 - это символ акции, столбец 2 - дата, столбец 3 - минуты, остальные - цены открытия-максимума-минимума-закрытия, объем и 3 целочисленных столбца.

Большинство запросов будут иметь вид «Назовите мне цены на AAPL с 12:15 12 апреля 2012 г. по 12:52 13 апреля 2012 г.»

Об оборудовании: я планирую использовать Amazon RDS, поэтому я могу гибко использовать это


5
Опишите ожидаемый типичный запрос
Уильям Перселл

10
«Я думаю, вам следует использовать MongoDB, потому что это веб-масштаб».
ta.speot.is

8
Вероятно, вам понадобится одна большая таблица, разделенная по символу акций.
ta.speot.is

1
Набор данных огромен! Вы можете поискать данные и аналитику, чтобы увидеть, что вы найдете.
Майк Перселл,

2
А «стандартной СУБД» с единственной таблицей для этого недостаточно? (Я имею дело только с миллионами, но «работает для меня». Можно просто попробовать и посмотреть. Не забудьте проиндексировать / кластер / раздел по мере необходимости.)

Ответы:


29

Расскажите нам о запросах и вашей аппаратной среде.

Мне очень хотелось бы перейти на NoSQL , используя Hadoop или что-то подобное, если вы можете использовать преимущества параллелизма.

Обновить

А почему?

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

  • Мой опыт работы с подобными системами предполагает, что доступ будет либо большим, последовательным (вычисление какого-то типа анализа временных рядов), либо очень очень гибким интеллектуальным анализом данных (OLAP). Последовательные данные можно обрабатывать лучше и быстрее последовательно; OLAP означает вычисление большого количества индексов, что займет много времени или много места.

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

  • Если вы хотите выполнять случайные запросы, особенно делать перекрестные сравнения, система Hadoop может оказаться эффективной. Почему? Потому как

    • вы можете лучше использовать параллелизм на относительно небольшом серийном оборудовании.
    • вы также можете лучше реализовать высокую надежность и избыточность
    • многие из этих проблем естественным образом поддаются парадигме MapReduce.

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


7
Какие преимущества предлагает здесь «NoSQL»? Почему в традиционной СУБД нет единой большой таблицы ? (С правильными индексами и т. Д.) Все говорят «NoSQL», «NoSQL», «NoSQL», но ... почему ?

5
Я должен сказать, что моим предложением также был бы подход NoSQL с использованием Apache Accumulo (это личное предпочтение). Небольшой набор данных (для Accumulo) и требуемый тип запросов идеально подходят для него с использованием его распределенного стека итератора.
Binary Nerd,

Спасибо за развернутый ответ. Я могу поставить +1.

2
Иногда некоторые комментарии меня просто сбивают с толку. '-1 за использование базы данных, где это не имеет смысла?' Весь ответ противоречит традиционной базе данных.
Чарли Мартин

52

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

Подготовьте структуру C / C ++ для хранения формата записи:

struct StockPrice
{
    char ticker_code[2];
    double stock_price;
    timespec when;
    etc
};

Затем вычислите sizeof (StockPrice [N]), где N - количество записей. (В 64-битной системе) Это должно быть всего несколько сотен гигабайт и поместиться на жесткий диск за 50 долларов.

Затем обрежьте файл до этого размера и mmap (в Linux или используйте CreateFileMapping в Windows) в память:

//pseduo-code
file = open("my.data", WRITE_ONLY);
truncate(file, sizeof(StockPrice[N]));
void* p = mmap(file, WRITE_ONLY);

Приведите указатель mmaped к StockPrice * и передайте данные, заполнив массив. Закройте mmap, и теперь у вас будут данные в одном большом двоичном массиве в файле, который позже можно будет снова добавить mmap.

StockPrice* stocks = (StockPrice*) p;
for (size_t i = 0; i < N; i++)
{
    stocks[i] = ParseNextStock(stock_indata_file);
}
close(file);

Теперь вы можете снова использовать mmap для чтения из любой программы, и ваши данные будут легко доступны:

file = open("my.data", READ_ONLY);
StockPrice* stocks = (StockPrice*) mmap(file, READ_ONLY);

// do stuff with stocks;

Итак, теперь вы можете рассматривать его как массив структур в памяти. Вы можете создавать различные типы структур данных индекса в зависимости от ваших «запросов». Ядро будет иметь дело с переносом данных на диск и с диска прозрачно, поэтому это будет безумно быстро.

Если вы ожидаете иметь определенный шаблон доступа (например, непрерывную дату), лучше всего отсортировать массив в этом порядке, чтобы он последовательно попадал на диск.


12
Потратьте несколько сотен, чтобы поместить его на SSD вместо жесткого диска. Случайное чтение примерно в сто раз быстрее. Или потратьте 10к на барана. Еще в сто раз быстрее
Стефан Эггермонт

1
@Andrew Tomazos, спасибо, чувак, это «
правильный

1
StockPrice sizeof будет char [4] = 4 байта int = 4 байта short = 2 байта float = 4 байта float = 4 байта float = 4 байта float = 4 байта float = 4 байта int = 4 байта int = 4 байта int = 4 байты ------------ 42 байта около 306,6 миллиарда байтов = ~ 285,5435013771057 ГБ памяти ... удачи с этим
ZagNut

3
@ZagNut: если вы подразумеваете, что вам нужно 300 ГБ физической памяти, то это неверно - mmap не копирует все в память, он загружает / выгружает ее по мере необходимости (так же, как файл подкачки) .
Эндрю Томазос

35

У меня есть набор данных за 1 минуту из 1000 акций, [...] большую часть (99,9%) времени я буду выполнять только запросы на чтение .

Одноразовое хранение и многократное считывание временных числовых данных - это вариант использования, называемый «временными рядами». Другими распространенными временными рядами являются данные датчиков в Интернете вещей, статистика мониторинга серверов, события приложений и т. Д.

Этот вопрос был задан в 2012 году, и с тех пор несколько движков баз данных разрабатывают функции специально для управления временными рядами. Я добился отличных результатов с InfluxDB , которая имеет открытый , написана на Go и лицензирована MIT.

InfluxDB был специально оптимизирован для хранения и запроса данных временных рядов. Намного больше, чем Кассандра , которую часто рекламируют как отличную для хранения временных рядов:

InfluxDB против скорости запроса Cassandra

Оптимизация временных рядов требует определенных компромиссов. Например:

Обновление существующих данных происходит редко, и никогда не бывает спорных обновлений. Данные временных рядов - это преимущественно новые данные, которые никогда не обновляются.

Плюсы: ограничение доступа к обновлениям позволяет повысить производительность запросов и записи.

Против: функциональность обновления значительно ограничена

В открытых источниках тестов ,

InfluxDB превзошел MongoDB во всех трех тестах с 27-кратным увеличением пропускной способности записи, при использовании в 84 раза меньшего дискового пространства и относительно одинаковой производительности, когда дело касалось скорости запросов.

InfluxDB против требований к дисковой памяти и сжатия MongoDB

Запросы тоже очень простые. Если ваши строки выглядят так <symbol, timestamp, open, high, low, close, volume>, с InfluxDB вы можете хранить только это, а затем легко запрашивать. Скажем, за последние 10 минут данных:

SELECT open, close FROM market_data WHERE symbol = 'AAPL' AND time > '2012-04-12 12:15' AND time < '2012-04-13 12:52'

Нет ни идентификаторов, ни ключей, ни объединений. Вы можете делать много интересных агрегатов . Вам не нужно вертикально разбивать таблицу, как в PostgreSQL , или преобразовывать вашу схему в массивы секунд, как в MongoDB . Кроме того, InfluxDB очень хорошо сжимает, в то время как PostgreSQL не сможет выполнить какое-либо сжатие для того типа данных, которые у вас есть .


1
Существуют и другие базы данных временных рядов, такие как kdb +, m3db или VictoriaMetrics , которые могут легко управлять триллионами строк на одном узле при рабочей нагрузке. См github.com/VictoriaMetrics/VictoriaMetrics/wiki/...
valyala

@valyala: VictoriaMetrics отлично выглядит! С тех пор, как я опубликовал это, у меня было множество проблем с InfluxDB ; хотя VictoriaMetrics вообще не поддерживает обновления :-(
Дэн Даскалеску

17

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

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

Затем вы добавляете кэширование - например, я предлагаю предоставить разным серверам разные запасы для обработки - и вы можете в значительной степени просто обслуживать из памяти. Если вы можете позволить себе достаточно памяти на достаточном количестве серверов, пропустите часть «загрузка по запросу» и просто загрузите все файлы при запуске. Это упростило бы задачу за счет более медленного запуска (что, очевидно, влияет на отработку отказа, если только вы не можете позволить себе всегда иметь два сервера для любого конкретного запаса, что было бы полезно).

Обратите внимание, что вам не нужно хранить биржевой символ, дату или минуту для каждой записи, потому что они неявны в загружаемом файле и позиции в файле. Вы также должны подумать, какая точность вам нужна для каждого значения и как ее эффективно хранить - вы указали 6SF в своем вопросе, который вы можете сохранить в 20 битах. Потенциально храните три 20-битных целых числа в 64-битном хранилище: прочтите его как long(или любое другое 64-битное целочисленное значение) и используйте маскировку / сдвиг, чтобы вернуть его к трем целым числам. Конечно, вам нужно знать, какой масштаб использовать - который вы, вероятно, могли бы закодировать в 4 запасных бита, если не можете сделать его постоянным.

Вы не сказали, на что похожи другие три целочисленных столбца, но если бы вы могли обойтись и для этих трех 64 бита, вы могли бы сохранить всю запись в 16 байтах. Это всего лишь ~ 110 ГБ для всей базы данных, что на самом деле не очень много ...

РЕДАКТИРОВАТЬ: Еще одна вещь, которую следует учитывать, заключается в том, что, по-видимому, акции не меняются за выходные - или, действительно, за ночь. Если фондовый рынок открыт только 8 часов в день, 5 дней в неделю, тогда вам нужно всего 40 значений в неделю вместо 168. На этом этапе вы можете получить только около 28 ГБ данных в ваших файлах ... намного меньше, чем вы, вероятно, думали изначально. Наличие такого количества данных в памяти очень разумно.

РЕДАКТИРОВАТЬ: Я думаю, что пропустил объяснение того, почему этот подход подходит здесь: у вас есть очень предсказуемый аспект для большой части ваших данных - биржевой тикер, дата и время. Выражая тикер один раз (как имя файла) и оставляя дату / время полностью неявными в позиции данных, вы удаляете целую кучу работы. Это немного похоже на разницу между a String[]и a Map<Integer, String>- знание того, что ваш индекс массива всегда начинается с 0 и увеличивается с шагом 1 до длины массива, обеспечивает быстрый доступ и более эффективное хранение.


Опять же, это зависит от того, как он использует данные. Если его запрос состоит в том, чтобы вытащить определенные данные по всем направлениям (с точки зрения символа акций), то это потребует чтения каждого файла и наличия определенных кодировок даты для извлечения правильных данных из каждого. Или, если он хочет, чтобы акции были наиболее эффективными за неделю, это было бы кошмаром с такой настройкой, когда приходилось читать все записи, сортировать и сравнивать. Без такой информации мы можем только догадываться, что это для фиксированного хранилища - может быть, как объемный DW, который в какой-то момент будет кормить отчетный DW (источник ETL).
Wolf5370

2
@ Wolf5370: Да, нам, безусловно, нужно знать, какие будут запросы, но у нас есть хоть какое-то указание на вопрос: «Большинство запросов будут такими:« Назовите мне цены на AAPL с 12 апреля 2012 г. с 12:15 до 13 апреля 2012 12:52 '. Было бы неплохо узнать, каковы будут другие запросы, а также относительные частоты и требования к производительности.
Джон Скит,

@JonSkeet, это действительно зависит от рабочей нагрузки, но у меня есть некоторые знания в этой области, и редко бывает просто «выбрать одну акцию из одного диапазона»: гораздо чаще «выбирать акции в этом портфеле из этого диапазона, вычислите & beta;, затем попробуйте этот список возможных акций и посмотрите, что такое & beta; ". Вот почему это подталкивает вас к чему-то подобному OLAP.
Чарли Мартин

2
@CharlieMartin: Ну, я просто следил за тем, что говорится в вопросе. Однако, если вы можете получить все это в памяти (на нескольких серверах), то это все еще довольно просто - спросите каждый сервер о соответствующих акциях в портфеле, а затем объедините результаты. Я думаю, что моя точка зрения об использовании известных аспектов данных (один раз в минуту, но не по выходным или в ночное время) по-прежнему полезна с точки зрения значительного уменьшения сложности получения всего этого в памяти.
Джон Скит

Это обсуждение напоминает мне цитату Фреда Брукса «Представление - это сущность программирования» и связанные с этим проблемы в «Жемчужине программирования» Бентли.
CS

14

Насколько я понимаю, HDF5 был разработан специально для хранения временных рядов складских данных в качестве одного из возможных приложений. Коллеги по укладке продемонстрировали, что HDF5 хорош для больших объемов данных: хромосом , физики .


2
+1 за конкретное решение. Однако мне нравится SQL DQL (по большей части) и гибкость, которую он предоставляет ... не уверен, что требуется от HDF5 для выхода из "иерархического представления".

4

Вот попытка создать сервер рыночных данных поверх базы данных Microsoft SQL Server 2012, который должен быть хорош для анализа OLAP, бесплатного проекта с открытым исходным кодом:

http://github.com/kriasoft/market-data


Ага. Не уверен, что этот конкретный проект применим, но определенно предложил бы OP рассмотреть структуру таблицы фактов OLAP или хранилища данных, оба подхода (иногда используемые вместе) предназначены для обработки такого рода данных с очень большим количеством строк. Это действительно зависит от того, какой анализ они собираются провести.
AaronLS

4

Во-первых, в году нет 365 торговых дней, а праздничные дни - 52 выходных (104) = скажем, 250 x фактическое количество часов дня, когда рынок открыт, как кто-то сказал, и использовать символ в качестве первичного ключа - не лучшая идея. поскольку символы меняются, используйте k_equity_id (числовой) с символом (char), поскольку символы могут быть такими, как этот A или GAC-DB-B.TO, тогда в ваших таблицах данных с информацией о ценах у вас есть, поэтому ваша оценка 7,3 миллиард сильно завышен, так как это всего 1,7 миллиона строк на символ за 14 лет.

k_equity_id k_date k_minute

и для таблицы EOD (которая будет просматриваться в 1000 раз больше других данных)

k_equity_id k_date

Во-вторых, не храните поминутные данные OHLC в той же таблице БД, что и таблица EOD (конец дня), поскольку любой, кто хочет посмотреть pnf или линейную диаграмму за год, не имеет никакого интереса к минутная информация.


3

Позвольте мне порекомендовать вам взглянуть на apache solr , который, я думаю, идеально подходит для вашей конкретной проблемы. По сути, вы сначала должны проиндексировать свои данные (каждая строка является «документом»). Solr оптимизирован для поиска и изначально поддерживает запросы диапазона по датам. Ваш именной запрос,

"Give me the prices of AAPL between April 12 2012 12:15 and April 13 2012 12:52"

переводится примерно так:

?q=stock:AAPL AND date:[2012-04-12T12:15:00Z TO 2012-04-13T12:52:00Z]

Предположим, что «stock» - это название акции, а «date» - это «DateField», созданное из столбцов «дата» и «минута» ваших входных данных при индексации. Solr невероятно гибок, и я действительно не могу сказать о нем достаточно хороших слов. Так, например, если вам необходимо сохранить поля в исходных данных, вы, вероятно, сможете найти способ динамически создать «DateField» как часть запроса (или фильтра).


Вы также можете использовать Amazon EC2 для настройки своего экземпляра solr
aliasmrchips

3
SOLR отлично подходит для поиска, но вам все равно нужно где-то хранить данные, чтобы заполнить индексы.
Майк Перселл,

Правда. Я предполагаю, что у Виктора П есть данные, и их нужно будет проиндексировать. Это потребует дополнительных ресурсов ... Впрочем, все предложенные подходы тоже годятся.
aliasmrchips

@aliasmrchips: я думаю, что подход InfluxDB работает лучше - он эффективно хранит (высокая пропускная способность, сжатие в 80 раз лучше, чем Mongo) и легко запрашивает.
Дэн Даскалеску

3

Я думаю, что с этим справится любая крупная СУБД. На атомарном уровне одна таблица с правильным разделением кажется разумной (разделение основано на использовании ваших данных, если оно исправлено - это, вероятно, либо символ, либо дата).

Вы также можете изучить создание агрегированных таблиц для более быстрого доступа выше атомарного уровня. Например, если ваши данные на уровне дня, но вы часто получаете данные на уровне wekk или даже месяца, то это можно предварительно рассчитать в сводной таблице. В некоторых базах данных это можно сделать с помощью кэшированного представления (различные имена для разных решений БД, но в основном это представление атомарных данных, но после запуска представление кэшируется / закрепляется в фиксированной временной таблице, которая запрашивается для последующих запросов соответствия Это может быть сброшено с интервалом, чтобы освободить память / место на диске).

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


3

Следует сравнить медленные решения с простой оптимизированной по памяти моделью. В несжатом виде он помещается в RAM-сервер на 256 ГБ. Снимок умещается в 32 КБ, и вы просто индексируете его позиционно по datetime и stock. Затем вы можете делать специализированные снимки, так как открытие одного часто равносильно закрытию предыдущего.

[править] Как вы думаете, почему вообще имеет смысл использовать базу данных (rdbms или nosql)? Эти данные не меняются и помещаются в памяти. Это не тот случай использования, когда dbms могут добавить ценность.


На самом деле, есть несколько причин, не в последнюю очередь из-за того, что если у вас 256 ГБ памяти, было бы неплохо, если бы было место для временного пространства, операционной системы и так далее. Затем возникают такие проблемы, как контрольные точки, ведение журнала и отказоустойчивость - как только вы начнете вычислять любые промежуточные результаты, вам снова понадобится управлять хранилищем. Я согласен с тем, что СУБД - не лучший выбор, но совершенно необходимо что-то более умное, чем «загрузка большого массива в память».
Чарли Мартин

контрольные точки, ведение журнала и отказоустойчивость чрезвычайно просты для почти статических данных. Звучит как идеальный вариант для решения в стиле превайлера
Стефан Эггермонт

Опять же, без лучшего знания приложения невозможно сказать наверняка, но в целом приложение не так статично, как вы думаете, потому что вы хотите поддерживать наборы результатов и потому что вы снова выполняете дорогостоящие вычисления с , контрольные точки и предварительно вычисленные частичные результаты.
Чарли Мартин

2

Если у вас есть оборудование, я рекомендую MySQL Cluster . Вы получаете интерфейс MySQL / RDBMS, с которым так хорошо знаком, и получаете быструю и параллельную запись. Чтение будет происходить медленнее, чем обычный MySQL, из-за задержки в сети, но у вас есть преимущество в возможности распараллеливать запросы и чтения из-за способа работы MySQL Cluster и механизма хранения NDB.

Убедитесь, что у вас достаточно машин MySQL Cluster и достаточно памяти / RAM для каждого из них - MySQL Cluster - это архитектура базы данных, в значительной степени ориентированная на память.

Или Redis , если вы не против использования интерфейса ключ-значение / NoSQL для чтения / записи. Убедитесь, что у Redis достаточно памяти - он сверхбыстрый для чтения и записи, с ним можно выполнять базовые запросы (хотя и не в РСУБД), но он также является базой данных в памяти.

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


2

Вы захотите, чтобы данные хранились в столбчатой ​​таблице / базе данных . Системы баз данных, такие как Vertica и Greenplum, представляют собой столбчатые базы данных, и я считаю, что SQL Server теперь позволяет использовать столбчатые таблицы. Они чрезвычайно эффективны для работы SELECTс очень большими наборами данных. Они также эффективны при импорте больших наборов данных.

Бесплатная колоночная база данных - это MonetDB .


1

Если ваш вариант использования заключается в простом чтении строк без агрегирования, вы можете использовать кластер Aerospike. Он находится в базе данных памяти с поддержкой файловой системы для сохранения. Он также оптимизирован для SSD.

Если вашему варианту использования нужны агрегированные данные, выберите кластер Mongo DB с сегментированием диапазона дат. Данные за год можно объединить в шарды.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.