Ваше приложение имеет те же характеристики, что и мое. Я написал собственный движок хранения MySQL для эффективного решения проблемы. Описано здесь
Представьте, что ваши данные размещены на диске в виде массива из 2M записей фиксированной длины (по одной на объект), каждая из которых содержит 3650 строк (по одной в день) по 20 байт (строка для одного объекта в день).
Ваш шаблон чтения читает одну сущность. Он непрерывен на диске, поэтому требуется 1 поиск (около 8 миллисекунд) и чтение 3650x20 = около 80 КБ со скоростью, возможно, 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 ЗАКАЗАТЬ (ENTITY, DAY)
Затем тот же самый SELECT занимает 198 миллисекунд (потому что он читает объект заказа в одном доступе к диску).
Однако операция ALTER TABLE заняла 13,98 дней (для 182M строк).
Есть еще несколько вещей, о которых говорят измерения
1. Ваш индексный файл будет таким же большим, как ваш файл данных. Это 3 ГБ для этой таблицы. Это означает (в моей системе) весь индекс на скорости диска, а не на скорости памяти.
2. Ваша ставка INSERT будет снижаться логарифмически. INSERT в файл данных является линейным, но вставка ключа в индекс - log. На 180M записях я получал 153 INSERT в секунду, что также очень близко к скорости поиска. Это показывает, что MySQL обновляет листовой индексный блок почти для каждой INSERT (как и следовало ожидать, поскольку он индексируется на сущности, но вставляется в порядке дня). Таким образом, вы смотрите на 2M / 153 секунды = 3,6 часа, чтобы выполнить ежедневную вставку 2M строк. (Разделенный на любой эффект, который вы можете получить по разделам между системами или дисками).