Ответ 1
Используйте partitioning. С вашим шаблоном чтения вы захотите разделить на entity_id
hash.
Как вы могли бы решить следующую проблему хранения и поиска?
Примерно 2.000.000 строк будут добавляться каждый день (365 дней/год) со следующей информацией в строке:
entity_id в сочетании с date_id уникален. Следовательно, в таблицу может быть добавлено не более одной строки на сущность и дату. База данных должна иметь возможность хранить 10-дневную ежедневную информацию (7,300,000,000 строк (3,650 * 2,000,000)).
То, что описано выше, - это шаблоны записи. Шаблон чтения прост: все запросы будут выполняться на определенном объекте_ид. То есть получить все строки, описывающие entity_id = 12345.
Поддержка транзакций не требуется, но решение для хранения должно быть открыто. В идеале я бы хотел использовать MySQL, но я открыт для предложений.
Теперь - как бы вы справились с описанной проблемой?
Обновление: Мне было предложено подробно рассказать о шаблонах чтения и записи. Записи в таблице будут выполняться в одной партии в день, когда новые записи 2M будут добавлены за один раз. Считывание будет производиться непрерывно с каждым чтением каждую секунду.
Используйте partitioning. С вашим шаблоном чтения вы захотите разделить на entity_id
hash.
"Теперь - как бы вы справились с описанной проблемой?"
С простыми плоскими файлами.
Вот почему
"все запросы будут выполняться на конкретный объект_ид. То есть извлекать все строки, описывающие entity_id = 12345."
У вас есть 2.000.000 объектов. Разделение на основе номера объекта:
level1= entity/10000
level2= (entity/100)%100
level3= entity%100
Каждый файл данных level1/level2/level3/batch_of_data
Затем вы можете прочитать все файлы в заданной части каталога, чтобы вернуть образцы для обработки.
Если кто-то хочет реляционную базу данных, загрузите файлы для данного объекта entity_id в базу данных для их использования.
Изменить В числовых номерах.
Правило уникальности date_id
/entity_id
не является чем-то, что нужно обрабатывать. Он (а) тривиально наложен на имена файлов и (б) не имеет отношения к запросу.
date_id
"опрокидывание" ничего не значит - нет запроса, поэтому нет необходимости переименовывать что-либо. date_id
должен просто расти без привязки к дате эпохи. Если вы хотите очистить старые данные, удалите старые файлы.
Поскольку никакой запрос не зависит от date_id
, с ним ничего не должно быть сделано. Это может быть имя файла для всего, что имеет значение.
Чтобы включить date_id
в результирующий набор, напишите его в файле с четырьмя другими атрибутами, которые находятся в каждой строке файла.
Изменить при открытии/закрытии
Для записи вам необходимо оставить файл открытым. Вы делаете периодические флеши (или закрываете/открываете), чтобы убедиться, что на самом деле что-то происходит на диске.
У вас есть два варианта архитектуры вашего автора.
У вас есть один "писательский" процесс, который объединяет данные из разных источников. Это полезно, если запросы относительно часты. Вы платите за объединение данных во время записи.
Несколько файлов открываются одновременно для записи. При запросе объедините эти файлы в один результат. Это полезно, потому что запросы относительно редки. Вы платите за объединение данных во время запроса.
Вы можете посмотреть на эти вопросы:
Большой первичный ключ: 1 + миллиард строк MySQL + InnoDB?
Лично я бы подумал о вычислении ширины строки, чтобы дать вам представление о том, насколько велика ваша таблица (согласно примечанию к секционированию в первой ссылке).
НТН.
S
Ваше приложение, похоже, имеет те же характеристики, что и мои. Я написал механизм пользовательского хранения MySQL для эффективного решения проблемы. Описывается здесь
Представьте, что ваши данные выложены на диске в виде массива записей фиксированной длины 2M (по одному на каждый объект), каждый из которых содержит 3650 строк (по одному в день) 20 байтов (строка для одного объекта в день).
Ваш шаблон чтения читает одно сущность. Он смежен на диске, поэтому требуется 1 поиск (около 8 мс) и чтение 3650x20 = около 80K, возможно, 100 Мбайт/с... так что это делается за долю секунды, что легко соответствует вашему 1-запросу в секунду чтению шаблон.
Обновление должно записать 20 байтов в 2M разных местах на диске. В простейшем случае это потребует 2M запросов, каждый из которых занимает около 8 миллисекунд, поэтому потребуется 2M * 8ms = 4,5 часа. Если вы будете распространять данные на 4-х дисках "raid0", это может занять 1,125 часов.
Однако места расположены всего на расстоянии 80 тысяч. В том случае, если в блоке размером 16 МБ имеется 200 таких мест (типичный размер кэша диска), он может работать на чем угодно до 200 раз быстрее. (1 минута) Реальность находится где-то между ними.
Мой механизм хранения работает с такой философией, хотя это немного более общая цель, чем массив с фиксированной длиной.
Вы можете точно указать, что я описал. Ввод кода в MySQL с возможностью подключения к хранилищу означает, что вы можете использовать MySQL для запроса данных с различными генераторами отчетов и т.д.
Кстати, вы можете исключить идентификатор даты и объекта из сохраненной строки (потому что это индексы массива) и может быть уникальным идентификатором - если вам это действительно не нужно, поскольку (идентификатор объекта, дата) уникально, и сохраните 2 значения как 3-байтовый int. Затем ваша сохраненная строка составляет 6 байт, и у вас есть 700 обновлений на 16 М и, следовательно, более быстрые вставки и меньший файл.
Изменить Сравнение с плоскими файлами
Я замечаю, что комментарии в целом предпочитают плоские файлы. Не забывайте, что каталоги - это просто индексы, реализованные файловой системой, и они, как правило, оптимизированы для относительно небольшого количества относительно больших элементов. Доступ к файлам, как правило, оптимизирован так, что он ожидает, что относительно небольшое количество файлов будет открыто, и имеет относительно высокие накладные расходы для открытого и закрытого и для каждого открытого файла. Все эти "относительно" относятся к типичному использованию базы данных.
Использование имен файловой системы в качестве индекса для идентификатора сущности, который я принимаю как не-разреженное целое число от 1 до 2 миллионов, противоречит интуиции. В программировании вы, например, использовали бы массив, а не хэш-таблицу, и вы неизбежно столкнетесь с большими накладными расходами на дорогостоящий путь доступа, который может быть просто операцией с массивом.
Поэтому, если вы используете плоские файлы, почему бы не использовать только один плоский файл и проиндексировать его?
Изменить по производительности
В производительности этого приложения будет преобладать время поиска диска. Вычисления, которые я сделал выше, определяют лучшее, что вы можете сделать (хотя вы можете сделать INSERT быстрее, замедляя SELECT - вы не можете сделать их лучше). Неважно, используете ли вы базу данных, плоские файлы или один плоский файл, кроме, которые вы можете добавить больше запросов, которые вам действительно не нужны, и замедлить их дальше. Например, индексирование (будь то индекс файловой системы или индекс базы данных) вызывает дополнительные операции ввода-вывода по сравнению с "поиском массива", и это замедлит работу.
Изменить на эталонных измерениях
У меня есть таблица, которая очень похожа на вашу (или почти точно как на один из ваших разделов). Это было 64 тыс. Единиц не 2М (1/32 твоего) и 2788 дней. Таблица была создана в том же порядке INSERT, что и ваш, и имеет тот же индекс (entity_id, day). SELECT на одном объекте занимает 20,3 секунды, чтобы проверить 2788 дней, что составляет около 130 запросов в секунду, как и ожидалось (на среднем диске времени поиска 8 миллисекунд). Время SELECT будет пропорционально количеству дней и не будет сильно зависеть от количества объектов. (Это будет быстрее на дисках с более быстрым временем поиска. Я использую пару SATA2 в RAID0, но это не имеет большого значения).
Если вы переупорядочиваете таблицу в порядке сущности ALTER TABLE x ORDER BY (ENTITY, DAY) Тогда тот же самый SELECT занимает 198 миллисекунд (потому что он считывает сущность заказа в одном доступе на диск). Однако для выполнения операции ALTER TABLE выполнено 13.98 дней (для строк 182M).
Есть еще несколько вещей, которые показывают вам измерения 1. Ваш индексный файл будет размером с ваш файл данных. Это 3 ГБ для этой таблицы образцов. Это означает, что (в моей системе) весь индекс на диске ускоряет скорость памяти.
2. Ваша ставка INSERT будет логарифмически уменьшаться. INSERT в файл данных является линейным, но вставка ключа в индекс - это журнал. На 180 М записей я получал 153 INSERT в секунду, что также очень близко к скорости поиска. Он показывает, что MySQL обновляет блок индекса листа почти для каждого INSERT (как и следовало ожидать, поскольку он индексируется по объекту, но вставляется в дневной порядок.). Таким образом, вы смотрите на 2M/153 secs = 3.6hrs, чтобы ежедневно вставлять строки в 2M. (Разделенный на любой эффект, который вы можете получить по разделам между системами или дисками).
У меня была аналогичная проблема (хотя и в гораздо большем масштабе - о вашем ежегодном использовании каждый день)
Используя один большой стол, я заставил себя замолчать до конца - вы можете тянуть несколько месяцев, но я думаю, вы в конечном итоге разделите его.
Не забудьте индексировать таблицу, иначе вы будете возиться с крошечной струйкой данных в каждом запросе; oh, и если вы хотите делать массовые запросы, использовать плоские файлы
Ваше описание шаблонов чтения недостаточно. Вам нужно будет описать, какие объемы данных будут извлечены, как часто и сколько будет отклонений в запросах.
Это позволит вам рассмотреть возможность сжатия в некоторых столбцах.
Также рассмотрите архивирование и разбиение.
Если вы хотите обрабатывать огромные данные с миллионами строк, его можно считать похожим на базу данных временных рядов, которая регистрирует время и сохраняет данные в базе данных. Некоторые из способов хранения данных - использование InfluxDB и MongoDB.