Вопрос

Как бы вы решили следующую проблему с хранением и извлечением данных?

Примерно 2.000.000 строк будут добавляться каждый день (365 дней в году) со следующей информацией для каждой строки:

  • идентификатор (уникальный идентификатор строки)
  • entity_id (принимает значения от 1 до 2.000.000 включительно)
  • date_id (увеличивается на единицу каждый день - будет принимать значения от 1 до 3.650 (десять лет:1*365*10))
  • значение_1 (принимает значения от 1 до 1.000.000 включительно)
  • значение_2 (принимает значения от 1 до 1.000.000 включительно)

entity_id в сочетании с date_id является уникальным.Следовательно, в таблицу может быть добавлена не более одной строки на объект и дату.База данных должна быть способна хранить ежедневные данные за 10 лет (7.300.000.000 строк (3.650 * 2.000.000)).

То, что описано выше, - это шаблоны записи.Схема чтения проста:все запросы будут выполняться по определенному entity_id.То есть.извлеките все строки, описывающие entity_id = 12345.

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

Теперь - как бы вы справились с описанной проблемой?

Обновить: Меня попросили подробнее рассказать о шаблонах чтения и записи.Записи в таблицу будут выполняться одним пакетом в день, при этом новые 2 МЛН записей будут добавлены за один раз.Чтения будут выполняться непрерывно, по одному чтению в секунду.

Это было полезно?

Решение

Использование разделение.С вашим шаблоном чтения вы бы хотели разделить на entity_id хэш.

Другие советы

"Теперь - как бы вы справились с описанной проблемой?"

С помощью простых плоских файлов.

И вот почему

"все запросы будут выполняться по определенному entity_id.То есть.извлеките все строки, описывающие entity_id = 12345."

У вас есть 2.000.000 сущностей.Разделение на основе номера объекта:

level1= entity/10000
level2= (entity/100)%100
level3= entity%100

Каждый файл данных представляет собой level1/level2/level3/batch_of_data

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

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


Редактировать По номерам дней.

  1. В date_id/entity_id правило уникальности заключается в не что-то, с чем нужно разобраться.Это (а) тривиально накладывается на имена файлов и (б) не имеет отношения к выполнению запросов.

  2. В date_id "ролловер" ничего не значит - запроса нет, поэтому нет необходимости что-либо переименовывать.В date_id должен просто расти без привязки к дате эпохи.Если вы хотите удалить старые данные, то удалите старые файлы.

Поскольку ни один запрос не полагается на date_id, с этим никогда ничего не нужно делать.Это может быть имя файла для всего, что имеет значение.

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


Редактировать при открытии / закрытии

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

У вас есть два варианта архитектуры вашего writer.

  1. Создайте единый процесс "записи", который объединяет данные из различных источников.Это полезно, если запросы относительно частые.Вы платите за объединение данных во время записи.

  2. Одновременно откройте несколько файлов для записи.При выполнении запроса объедините эти файлы в единый результат.Это полезно, поскольку запросы относительно редки.Вы платите за объединение данных во время запроса.

Возможно, вы захотите взглянуть на эти вопросы:

Большой первичный ключ:1+ миллиард строк MySQL + InnoDB?

Большие таблицы MySQL

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

ХТХ.,

S

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

Представьте, что ваши данные размещены на диске в виде массива из записей фиксированной длины 2 М (по одной на объект), каждая из которых содержит 3650 строк (по одной в день) по 20 байт (строка для одного объекта в день).

Ваш шаблон чтения считывает один объект.Он находится на диске непрерывно, поэтому требуется 1 поиск (около 8 миллисекунд) и чтение 3650x20 = около 80 КБ со скоростью, возможно, 100 Мбит / с...таким образом, это делается за доли секунды, легко соответствуя вашему шаблону чтения с частотой 1 запрос в секунду.

Обновление должно записать 20 байт в 2 МЛН разных мест на диске.В простейшем случае это заняло бы 2 М поисков, каждый из которых занимает около 8 миллисекунд, так что это заняло бы 2 М * 8 мс = 4,5 часа.Если вы распределите данные по 4 дискам “raid0”, это может занять 1,125 часа.

Однако эти места находятся всего в 80 км друг от друга.Это означает, что в блоке размером 16 МБ имеется 200 таких мест (типичный размер дискового кэша), так что он может работать с любой скоростью до 200 раз быстрее.(1 минута) Реальность находится где-то между этими двумя понятиями.

Мой механизм хранения данных работает на основе такого рода философии, хотя он немного более общего назначения, чем массив фиксированной длины.

Вы могли бы закодировать именно то, что я описал.Помещение кода в MySQL pluggable storage engine означает, что вы можете использовать MySQL для запроса данных с помощью различных генераторов отчетов и т.д.

Кстати, вы могли бы исключить дату и идентификатор объекта из сохраненной строки (поскольку они являются индексами массива) и могут быть уникальным идентификатором – если вам это действительно не нужно, поскольку (идентификатор объекта, дата) уникален, и сохранить 2 значения как 3-байтовый int.Тогда ваша сохраненная строка составляет 6 байт, и у вас 700 обновлений на 16 МБ и, следовательно, более быстрые вставки и файл меньшего размера.

Редактировать Сравнение с плоскими файлами

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

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

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

Редактировать о производительности

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

Редактировать об эталонных измерениях

У меня есть таблица, которая очень похожа на вашу (или почти точно похожа на один из ваших разделов).Это было 64 тысячи сущностей, а не 2 МИЛЛИОНА (1/32 ваших), и 2788 "дней".Таблица была создана в том же порядке вставки, что и ваша, и имеет тот же индекс (entity_id,day).Выбор одного объекта занимает 20,3 секунды для проверки 2788 дней, что составляет около 130 запросов в секунду, как и ожидалось (на дисках со средним временем поиска 8 миллисекунд).ВЫБРАННОЕ время будет пропорционально количеству дней и не сильно зависеть от количества объектов.(Это будет быстрее на дисках с более быстрым временем поиска.Я использую пару SATA2 в RAID0, но это не имеет большого значения).

Если вы переупорядочите таблицу в порядок объектов ИЗМЕНИТЕ ПОРЯДОК ТАБЛИЦЫ x НА (ОБЪЕКТ, ДЕНЬ) Тогда тот же выбор займет 198 миллисекунд (поскольку он считывает объект order при доступе к одному диску).Однако для завершения операции ALTER TABLE потребовалось 13,98 ДНЕЙ (для 182 млн строк).

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

2. Скорость вашей вставки будет снижаться логарифмически.Вставка в файл данных является линейной, но вставка ключа в индекс является логарифмической.При 180-метровых записях я получал 153 вставки в секунду, что также очень близко к скорости поиска.Это показывает, что MySQL обновляет конечный индексный блок почти для каждой вставки (как и следовало ожидать, потому что он индексируется в entity, но вставляется в дневном порядке.).Итак, вам требуется 2 м / 153 секунды = 3,6 часа для ежедневной вставки 2 м строк.(Разделенный на любой эффект, который вы можете получить, разделяя системы или диски).

У меня было аналогичная проблема (хотя и в гораздо большем масштабе - о вашем годовом использовании каждый день)

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

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

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

Это позволит вам рассмотреть возможность выполнения сжатия для некоторых столбцов.

Также рассмотрите возможность архивирования и разбиения на разделы.

Если вы хотите обрабатывать огромные данные с миллионами строк, это можно рассматривать как аналог базы данных временных рядов, которая регистрирует время и сохраняет данные в базе данных.Некоторые из способов хранения данных используют InfluxDB и MongoDB.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top