LINUX.ORG.RU

В какой СУБД хранить сложные структуры данных?


0

1

Добрый день. Есть такая структура данных:

{
  key_number_1: {
      key_date_1: [
           {'min': 125,
            'max': 300},
           {'min': 10,
            'max': 15},
           {'min': 15,
            'max': 20,}
           ...
           {'min': 0,
            'max': 10},
        ],
      key_date_2: [
           {'min': 125,
            'max': 300},
           ...
           {'min': 10,
            'max': 15},
        ],
     ...
      key_date_3: [
           {'min': 600,
            'max': 800},
           ...
           {'min': 90,
            'max': 100},
        ],
    }
  key_number_2: {
      key_date_1: [
           {'min': 10,
            'max': 40},
           ...
           {'min': 0,
            'max': 10},
        ],
      key_date_2: [
           {'min': 125,
            'max': 300},
           {'min': 10,
            'max': 15},
        ],
     ...
      key_date_3: [
           {'min': 600,
            'max': 800},
           ...
           {'min': 110,
            'max': 111},
    }
}
Мне нужно извлекать по key_number_* и key_date_* все или часть элементов, которые находятся на третьем уровне. Т.е. словари {min: ..., max: ...}

Решением «в лоб» было создание одной «плоской» таблицы с такой структурой:

id
number
date
min
max
В качестве СУБД использую MySQL, тип таблицы — MyISAM. Сделал составные индексы (number date). Текущий размер таблицы около 12 ГБ, количество строк около 200 млн. Выборка происходит очень долго.

Одной из идей как увеличить быстродействие было разнести данные по key_number_* и key_number_ в отдельные таблицы. Название таблиц — Table{$key_number}_{$str_key_date}. От этой идеи отказался, так как будет трудно делать выборку по key_number_*, игнорируя key_number_* из-за того, что появится куча таблиц, названия которых придется получать, как-то отделять номер от даты.

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

Сейчас выбираю себе нереляционное СУБД. Пока что по документации:

  • Redis — простая БД для хранения ключ -> значение;
  • CouchDB — умеет хранить данные в формате JSON, но не понятно, может ли быстро извлекать данные;
  • MongoDB — судя по документации, у меня сложилось впечатление, что эта штука нужна для создания «плоских» таблиц без структуры. По идеи можно перенести данные с MySQL, но не думаю, что быстродействие увеличится.

Собственно вопрос в том, какую СУБД мне выбрать?


Эта структура вписывается в файловую систему:

root_dir/ --> key_number_1/ --> key_date_1/ --> file0, file1, ... (содержимое файла 0 --> min': 125, 'max': 300)
                            --> key_date_2/ --> file0, file1, ... (содержимое файла 0 --> min': 125, 'max': 300)
          --> key_number_2/ --> key_date_1/...

anonymous ()
Ответ на: комментарий от anonymous

Полагаю, что такой вариант подойдет, если файлов будет не много. А у меня в базу данных пишется для каждого key_date_* и key_number_* около 3000 строк. Создание мелких 3000 файлов мне кажется нерациональной нагрузкой на файловую систему.

dicos ()

12 гиг и долго? купи железку по мощнее, дикс быстрее и памяти по больше.

ukr_unix_user ★★★★ ()
Ответ на: комментарий от ukr_unix_user

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

dicos ()

postgresql ещё не предлагали с партицирование данных по условию?

Atlant ★★★★★ ()
Ответ на: комментарий от Atlant

P.S. есть возможность создать свои типы данных, их ограничения, функции по работе с данными типами.
P.P.S. более дорогостоящей и 'возможно' более скоростной возможностью является OracleDB

Atlant ★★★★★ ()
Последнее исправление: Atlant (всего исправлений: 2)

Посмотри couchbase. Очень быстрая и умеет map раскидывать по нодам.

monk ★★★★★ ()

Насколько я помню - монго умеет делать выборки по «глубинным» условиям и даже строить по ним индексы. Почитай внимательно доки. Только внимательно читай про многопоточность - у них были проблемы типа «у нас есть mapreduce, но он работает только на одном ядре и пепячит порционный global write lock». Но когда нет таблиц миллионников или (100к+оч много запросов) то на недостатки монги можно забить и радоваться действительно удобным фичам.

Если юзаешь rails или ruby - есть удобный ORM - mongoid.

mr_ffloyd ()

сколько занимает одна строка? 20 байт?
может и не нужна субд - в память все влезет

x905 ★★★★★ ()
Ответ на: комментарий от x905

mongo и так приемущественно в памяти живет. А ложить в память используя стандартные структуры языка и самому писать поиск - можно, только если объемы данных не увеличатся на порядки (100к еще ок, думаю, но тут зависит от скорости языка и знания алгоритмов).

mr_ffloyd ()

монга идеально подходит, почитай еще раз

trashymichael ★★★ ()
Ответ на: комментарий от dicos

Создание мелких 3000 файлов мне кажется нерациональной нагрузкой на файловую систему.

для ext3/4 это мелочь. Сложности возникали у меня если файлов >10M. Да и то, в СУБД было не лучше.

drBatty ★★ ()

MongoDB жрёт JSON, как раз то, что есть у тебя в начале поста. Попробуй, может и взлетит.

Norgat ★★★★★ ()

насколько большой словарь по каждому ключу(number,date)?

меняется ли словарь?(кроме их частого чтения , насколько часто меняется одна/несколько пар?)

чем неудобен вариант 1 таблицы с 3 полями
1. key_number
2. key_date
3. big_raw_data

?

qulinxao ★★☆ ()

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

а так я бы советовал LDAP.

cvv ★★★★★ ()

Сейчас выбираю себе нереляционное СУБД

Можешь попробовать GT.M. Не мэйнстрим, но базируется на широко известном (в узких кругах) (в постсоветском пространстве) MUMPSе.

gag ★★★★★ ()
Ответ на: комментарий от qulinxao

Не подходит вариант по двум причинам:

  • Кроме полей min и max еще есть куча полей, по которым нужно осуществлять поиск. Я считаю, что поиском должна заниматься СУБД.
  • Данные пишутся в течении дня, (что-то наподобие логов). И сливать ночью кучу данных в одно поле big_raw_data, так как порой, ночные задания могут не проходить.

Сейчас специально посчитал за вчерашний день примерно 43750 на каждый ключ. 350000 строк в день

dicos ()
Ответ на: комментарий от x905

не войдет, так как строк на текущий момент 109 966 215

dicos ()
Ответ на: комментарий от Atlant

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

dicos ()
Ответ на: комментарий от dicos

покури какие десигндесишен для тяжелонагруженных логеров.

qulinxao ★★☆ ()
Ответ на: комментарий от cvv

Предлагаешь в качестве имени файла использовать дату+время+ миллисекунды?

dicos ()

kdb же .

/тред не читал

anonymous ()

а что за данные-то, о чём база? json конечно интересно и модно, но реляционную модель по нему не сделать.

PS. «Название таблиц — Table{$key_number}_{$str_key_date}» говорит о срочной затребованности основополагающей литературки для ТС

MKuznetsov ★★★★★ ()
Ответ на: комментарий от dicos

Предлагаешь в качестве имени файла использовать дату+время+ миллисекунды?

могу тебя сразу расстроить, если тебе нужны запросы типа «от 4 до 57», то про ФС забудь. ФС даст ответ только на вопрос «ТОЧНО 34»

drBatty ★★ ()

Используй ROOT tree. http://en.wikipedia.org/wiki/ROOT

A key feature of ROOT is a data container called tree, with its substructures branches and leaves. ROOT is designed for high computing efficiency, as it is required to process data from the Large Hadron Collider's experiments estimated at several petabytes per year.

Alex-Alex ()
Ответ на: комментарий от MKuznetsov

Хочу сделать торгового робота, который будет автоматически торговать на рынке ценных бумаг.

В базе данных хранятся названия бумаг, цена, время покупки. + еще куча служебной информации.

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

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

dicos ()
Ответ на: комментарий от mr_ffloyd

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

если выборка только по key_number и key_date, сгодится струкура вида
{
key: 'key_number_1',
date: 'key_date_1',
data: [{min: 125, 'max': 300},{min: 70, 'max': 85}]
}

и индекс db.collection.ensureIndex({ key: 1, date: -1 });

если min/max много - можно денормализовать данные до конца.

какая планируется нагрузка чтение/запись?

VladimirMalyk ★★★★★ ()

min-max надо хранить как пару 32-битных целых чисел в двоичном виде. Соответственно, все такие пары за день можно хранить вместе, одну за другой, в файле. Вообще можно делать один файл на неделю по каждой позиции. В заголовке - смещение дней внутри файла. Будет очень быстрая выборка всех мин-макс за любой день по любой позиции, потому что минимум обращений к диску. И даже можно динамически добавлять новые значения по ходу дела. И даже менять старые. Только удалять будет немножко сложно.

Deleted ()

Текущий размер таблицы около 12 ГБ, количество строк около 200 млн. Выборка происходит очень долго

А, кстати, на всякий случай, оперативки установлено около 16 ГБ?

gag ★★★★★ ()
Ответ на: комментарий от dicos

вот с этого и надо начинать..

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

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

MKuznetsov ★★★★★ ()
Ответ на: комментарий от dicos

Дык min-max упаковываются в int32. Ну и покажи структуру базы (explain table или как там) и пример запросов.

true_admin ★★★★★ ()

Datomic, Neo4j хз как с производительностью у обоих, но скоро узнаю :)

Вообще 12Г записей не должно тормозить. Я бы попробовал сначала поиграть с настройками mysql.

zz ★★★★ ()

напиши парсер, преобразующий в оптимальную структуру или просто преобразуй в yaml/json

если нужно обращаться к полям в запросах, то либо in-memory либо postgresql с типом данных array (можно будет обращаться к полям массива прямо в запросах - имхо лучшего решения как у слона не встречал)

извратный вариант: преобразовать все в «плоский вид» что можно и зафигачить все в колонки т.е. равернуть один уровень по горизонтали.

nosql те-же яйца только вид через замочную скважину...

anonymous ()

KDB+ уже советовали?

anonymous ()

Всех благодарю за участие в обсуждении. Сейчас залез в настройки MySQL и увеличил потребление оперативной памяти. Запросы начали выполняться значительно быстрее. Пока что быстродействия хватает.

dicos ()

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

Я бы сделал так:

1. Распилил таблицу на две, первая бы стала headers(id,number,date), в ней два UNIQUE INDEX на (number,date) и (date,number)

2. Сделал таблицу для собственно данных (id,headerid,min,max) и constraint headerid_fk foreign key (headerid) references headers(id). И естественно + индекс по headerid

Таблицы при этом резко сожмутся в размерах (в байтах).

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

Минусы будет на сложных запросах с условиями на min+max.

no-dashi ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.