Оригинальный вопрос
Фон
Хорошо известно, что SQLite нуждается в настройке для достижения скорости вставки порядка 50 тыс. вставок/с. Здесь много вопросов относительно медленных скоростей вставки и большого количества советов и тестов.
Есть также утверждает, что SQLite может обрабатывать большие объемы данных, с отчетами о 50+ ГБ, не вызывающими проблем с правильными настройками.
Я следил за советами здесь и в других местах, чтобы достичь этих скоростей, и я доволен вставками 35k-45k. Проблема в том, что все эталонные тесты демонстрируют только быстрые скорости вставки с < 1 м записей. Я вижу, что скорость вставки, по-видимому, обратно пропорциональна размеру таблицы.
Вопрос
В моем случае использования требуется хранить от 500 до 1 бит кортежей ([x_id, y_id, z_id]
) в течение нескольких лет (1 м строк/день) в таблице ссылок. Значения представляют собой целые идентификаторы от 1 до 2 000 000. На z_id
есть один индекс.
Производительность отлично подходит для первых 10-миллиметровых строк, ~ 35 тыс. вставок/с, но к тому времени, когда таблица имеет ~ 20 м строк, производительность начинает страдать. Теперь я вижу около 100 вставок/с.
Размер таблицы не очень большой. С 20-метровыми рядами размер на диске составляет около 500 МБ.
Проект написан на Perl.
Вопрос
Является ли это реальностью больших таблиц в SQLite или есть какие-то секреты для поддержания высоких ставок вставки для таблиц s > 10 м строк?
Известные обходные пути, которые я хотел бы избежать, если возможно
- Отбросьте индекс, добавьте записи и переиндексируйте: это нормально в качестве обходного пути, но не работает, когда БД все еще необходимо использовать во время обновлений. Это не сработает, чтобы сделать базу данных полностью недоступной для x минут/дней
- Разбить таблицу на более мелкие субтитры/файлы: это будет работать в краткосрочной перспективе, и я уже экспериментировал с ним. Проблема в том, что мне нужно иметь возможность извлекать данные из всей истории при запросе, что означает, что в конечном итоге я удалю ограничение 62 привязки таблицы. Прикрепление, сбор результатов в таблице temp и отключение сотен раз за запрос, кажется, много работы и накладных расходов, но я попробую, если нет других альтернатив.
- Установить
SQLITE_FCNTL_CHUNK_SIZE
: я не знаю C (?!), поэтому я бы предпочел не изучать его только для того, чтобы сделайте это. Я не вижу способа установить этот параметр с помощью Perl.
UPDATE
После предложения Тима, что индекс все чаще вызывал медленное время вставки, несмотря на то, что SQLite утверждает, что он способен обработки больших наборов данных, я провел сравнительное сравнение со следующими Параметры:
- вставленные строки: 14 миллионов
- фиксировать размер партии: 50 000 записей
-
cache_size
прагма: 10 000 -
page_size
прагма: 4 096 -
temp_store
прагма: память -
journal_mode
прагма: удалить -
synchronous
прагма: выкл
В моем проекте, как и в приведенных ниже результатах теста, создается временная таблица на основе файлов и встроенная поддержка SQLite
для импорта данных CSV. Затем прилагается временная таблица
к принимающей базе данных и наборам из 50 000 строк вставляются с
insert-select
. Следовательно, времена вставки не отражают
файл для вставки в базу данных, но вместо таблицы в таблицу
скорость. Принимая во внимание время импорта CSV, можно уменьшить скорость
на 25-50% (очень приблизительная оценка, не требуется много времени для импорта
CSV).
Очевидно, что наличие индекса приводит к замедлению скорости вставки при увеличении размера таблицы.
Из приведенных выше данных видно, что правильный ответ может быть отнесен к ответу Тима, а не утверждениям, что SQLite просто не может его обработать. Очевидно, что он может обрабатывать большие наборы данных, если индексирование этого набора данных не является частью вашего прецедента. Я использую SQLite только для этого, как для бэкэнд для системы ведения журнала, какое-то время, которое не нужно индексировать, поэтому я был очень удивлен замедлением, которое я испытал.
Заключение
Если кто-то обнаруживает, что хочет хранить большой объем данных с помощью SQLite и индексировать его, используя осколкиможет быть ответом. В конце концов я решил использовать первые три символа хэша MD5 в столбце z
, чтобы определить назначение одной из 4096 баз данных. Поскольку мой вариант использования носит преимущественно архивный характер, схема не изменится, и запросы никогда не потребуют шаринговой ходьбы. Ограничение по размеру базы данных ограничено, так как чрезвычайно старые данные будут уменьшены и в конечном итоге будут отброшены, поэтому эта комбинация параметров sharding, pragma и даже некоторая денормализация дает мне хороший баланс, который, основываясь на сравнительном анализе выше, поддерживает скорость вставки не менее 10 тыс. вставок в секунду.