Каковы характеристики производительности sqlite с очень большими файлами базы данных? [закрыто]

325

Я знаю, что sqlite не очень хорошо работает с очень большими файлами баз данных, даже если они поддерживаются (на веб-сайте sqlite был комментарий о том, что если вам нужны файлы размером более 1 ГБ, вы можете рассмотреть возможность использования корпоративных rdbms. больше не могу найти, может быть связано с более старой версией sqlite).

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

Я говорю о файлах данных sqlite в диапазоне нескольких гигабайт, начиная с 2 ГБ. У кого-нибудь есть опыт с этим? Любые советы / идеи?

Snazzer
источник
1
Использование потоков (соединение на поток) может помочь только для чтения - stackoverflow.com/a/24029046/743263
malkia
23
Год 2016: у меня есть база данных 5 ГБ, которая работает на SQLite без проблем. Я установил точно такой же набор данных на Postgres. SQLite выполнил сложный запрос за 2,7 мс, Postgres за 2,5 мс. Я остановился на Postgres для облегчения доступа к Regex и улучшения функций индексирования. Но я был впечатлен SQLite и мог бы также использовать его.
Полб

Ответы:

246

Поэтому я провел несколько тестов с sqlite для очень больших файлов и пришел к некоторым выводам (по крайней мере, для моего конкретного приложения).

В тестах используется один файл sqlite с одной или несколькими таблицами. В каждой таблице было около 8 столбцов, почти все целые числа и 4 индекса.

Идея заключалась в том, чтобы вставить достаточно данных, пока размер файлов sqlite не достигнет 50 ГБ.

Одноместный стол

Я попытался вставить несколько строк в файл sqlite только с одной таблицей. Когда размер файла составлял около 7 ГБ (извините, я не могу точно сказать, сколько строк) вставки занимали слишком много времени. Я подсчитал, что мой тест для вставки всех моих данных займет около 24 часов, но он не завершился даже после 48 часов.

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

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

Несколько столов

Затем я попытался разделить данные по времени на несколько таблиц, по одной таблице в день. Данные для исходной таблицы 1 были разделены на ~ 700 таблиц.

У этой настройки не было проблем со вставкой, она не занимала больше времени, так как новая таблица создавалась для каждого дня.

Проблемы с вакуумом

Как указано в i_like_caffeine, команда VACUUM является проблемой, когда файл sqlite больше. По мере выполнения большего количества операций вставки / удаления фрагментация файла на диске будет ухудшаться, поэтому цель состоит в том, чтобы периодически VACUUM оптимизировать файл и восстанавливать файловое пространство.

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

Выводы

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

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

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

Жаль, что, похоже, нет другого метода добавочного вакуума, кроме автоматического вакуума . Я не могу использовать его, потому что моя цель для вакуума - дефрагментировать файл (файловое пространство не имеет большого значения), чего не делает автоматический вакуум. Фактически, в документации говорится, что это может ухудшить фрагментацию, поэтому мне приходится периодически прибегать к созданию полного вакуума в файле.

Snazzer
источник
5
Очень полезная информация Чистое предположение, но мне интересно, можно ли использовать новый API резервного копирования для ежедневного создания нефрагментированной версии вашей базы данных и избежать необходимости запуска VACUUM.
eodonohoe
24
Мне любопытно, были ли все ваши ВСТАВКИ в транзакции?
Поль Лефевр
9
Да, вставки выполнялись партиями по 10000 сообщений на транзакцию.
Snazzer
6
Какую файловую систему вы использовали? Если ext {2,3,4}, что было параметром data =, было ли включено ведение журнала? Помимо шаблонов ввода / вывода, способ сброса sqlite на диск может быть значительным.
Тобу
5
Я тестировал в основном на Windows, поэтому не могу комментировать поведение на Linux.
Snazzer
169

Мы используем DBS 50 ГБ + на нашей платформе. без жалоб работает отлично. Убедитесь, что вы все делаете правильно! Вы используете предопределенные заявления? * SQLITE 3.7.3

  1. операции
  2. Предварительно сделанные заявления
  3. Примените эти настройки (сразу после создания БД)

    PRAGMA main.page_size = 4096;
    PRAGMA main.cache_size=10000;
    PRAGMA main.locking_mode=EXCLUSIVE;
    PRAGMA main.synchronous=NORMAL;
    PRAGMA main.journal_mode=WAL;
    PRAGMA main.cache_size=5000;
    

Надеюсь, что это поможет другим, отлично работает здесь

Alex
источник
22
Недавно протестирован с БД в диапазоне 160 ГБ, прекрасно работает.
Snazzer
10
Также PRAGMA main.temp_store = MEMORY;.
Викрант Чаудхари
40
@ Алекс, почему есть два PRAGMA main.cache_size = 5000 ;?
Джек
23
Не просто слепо применять эти оптимизации. В частности синхронный = НОРМАЛЬНЫЙ не является безопасным при сбое. То есть сбой процесса в нужное время может повредить вашу базу данных даже при отсутствии сбоев диска. sqlite.org/pragma.html#pragma_synchronous
MPM
22
@ Алекс, не могли бы вы объяснить эти значения и разницу между ними и значениями по умолчанию?
4m1nh4j1
65

Я создал базы данных SQLite размером до 3,5 ГБ без каких-либо заметных проблем с производительностью. Если я правильно помню, я думаю, что у SQLite2 могли быть некоторые более низкие пределы, но я не думаю, что у SQLite3 есть такие проблемы.

Согласно странице ограничений SQLite , максимальный размер каждой страницы базы данных составляет 32 КБ. А максимальное количество страниц в базе данных составляет 1024 ^ 3. Так что по моей математике получается 32 терабайта как максимальный размер. Я думаю, что вы достигнете пределов своей файловой системы, прежде чем поразите SQLite!

Поль Лефевр
источник
3
В зависимости от того, какие операции вы выполняете, пытаясь удалить 3000 строк в базе данных sqlite 8G, вам потребуется достаточно времени, чтобы приготовить хороший горшок с французской прессой, lol
benjaminz,
4
@benjaminz, ты, должно быть, делаешь это неправильно. Если вы оберните удаление 3k строк в одну транзакцию, это должно быть почти мгновенно. Я сам допустил эту ошибку: удаление 10 тысяч строк по одной заняло 30 минут. Но как только я обернул все операторы удаления в одну транзакцию, это заняло 5 секунд.
MVP
55

Во многом причина того, что на вставку> 48 часов ушло из-за ваших индексов. Это невероятно быстрее:

1 - удалить все индексы 2 - сделать все вставки 3 - снова создать индексы

user352992
источник
23
Это хорошо известно ... но для длительного процесса вы не будете периодически отбрасывать свои индексы, чтобы перестраивать их, особенно когда вы будете запрашивать их для выполнения работы. Такой подход используется, хотя, когда sqlite db нужно перестраивать с нуля, индексы создаются после того, как все вставки сделаны.
Snazzer
24
В аналогичной ситуации @Snazzer мы использовали таблицу «аккумуляторов»: раз в день мы перемещали накопленные строки из таблицы аккумуляторов в основную таблицу в рамках одной транзакции. Там, где это было необходимо, представление позаботилось о представлении обеих таблиц как одной таблицы.
CAFxX
4
Другой вариант - сохранить индексы, но предварительно отсортировать данные в порядке индекса перед тем, как вставить их.
Стивен Крыскалла
1
@StevenKryskalla как это сравнить с отбрасыванием индексов и их воссозданием? Какие-нибудь ссылки, которые вы знаете об этом, были оценены?
mcmillab
1
@mcmillab Это было много лет назад, поэтому я не помню все детали или статистические показатели, но, думая интуитивно, вставка N случайно упорядоченных элементов в индекс займет O (NlogN) времени, а вставка N отсортированных элементов - O (N Время
Стивен Крыскалла
34

Помимо обычной рекомендации:

  1. Падение индекса для массовой вставки.
  2. Пакетные вставки / обновления в больших транзакциях.
  3. Настройте свой буферный кеш / отключите журнал / w PRAGMA.
  4. Используйте 64-битную машину (чтобы иметь возможность использовать много кеша ™).
  5. [добавлено в июле 2014 г.] Используйте общее табличное выражение (CTE) вместо выполнения нескольких SQL-запросов! Требуется версия SQLite 3.8.3.

Из моего опыта работы с SQLite3 я узнал следующее:

  1. Для максимальной скорости вставки не используйте схему с каким-либо ограничением столбца. (Изменить таблицу позже по мере необходимости Вы не можете добавить ограничения с помощью ALTER TABLE).
  2. Оптимизируйте свою схему, чтобы хранить то, что вам нужно. Иногда это означает разрушение таблиц и / или даже сжатие / преобразование ваших данных перед вставкой в ​​базу данных. Отличным примером является хранение IP-адресов в виде (длинных) целых чисел.
  3. Одна таблица на файл базы данных - чтобы минимизировать конфликт блокировки. (Используйте ATTACH DATABASE, если вы хотите иметь один объект подключения.
  4. SQLite может хранить различные типы данных в одном столбце (динамическая типизация), используйте это в своих интересах.

Вопрос / комментарий приветствуется. ;-)

Лестер Чунг
источник
1
Какое влияние вы получите от «одной таблицы на файл БД»? Звучит интересно. Как вы думаете, это будет иметь большое значение, если ваша таблица имеет только 3 таблицы и строится с нуля?
Мартин Велес
4
@martin ненавижу это говорить, но ответ - это зависит . Идея состоит в том, чтобы разделить данные до управляемого размера. В моем случае использования я собираю данные с разных хостов и готовлю отчеты по фактам, чтобы этот подход работал хорошо. Разделение по дате / времени, как предлагают другие, должно хорошо работать для данных, охватывающих длительный период времени, который я себе представляю.
Лестер Чунг
3
@Lester Cheung: Что касается вашего второго # 1: Насколько я понимаю из документации и личного опыта, по сей день SQLite3 не поддерживает добавление ограничений с помощью ALTER TABLE после создания таблицы. Единственный способ добавить или удалить ограничения из существующих строк таблицы - создать новую таблицу с требуемыми характеристиками и скопировать все строки, что, вероятно, будет намного медленнее, чем однократная вставка с ограничениями.
Mumbleskates
3
@Widdershins вы абсолютно правы - ALTER TABLE в SQLite не позволяет добавлять ограничения. Я не знаю, что я курил - обновлю ответ - спасибо.
Лестер Чунг
Ни одно из этих предложений не имеет ничего общего с использованием огромных файлов SQLite db. Был ли вопрос отредактирован с момента отправки этого ответа?
А. Рейгер
9

Я думаю, что основные жалобы по поводу масштабирования sqlite:

  1. Единый процесс записи.
  2. Нет зеркалирования.
  3. Нет тиражирования.
неизвестный
источник
9

У меня есть база данных SQLite 7 ГБ. Для выполнения определенного запроса с внутренним объединением требуется 2,6 с. Чтобы ускорить это, я попытался добавить индексы. В зависимости от того, какие индексы я добавил, иногда запрос снижался до 0,1 с, а иногда до 7 с. Я думаю, что проблема в моем случае заключалась в том, что если столбец сильно дублируется, то добавление индекса снижает производительность :(

Майк Оксинормас
источник
9
Почему столбец с множеством дубликатов ухудшает производительность (серьезный вопрос)?
Мартин Велес
6
труднее индексировать столбец с низким количеством
элементов
9

В документации SQLite существовало утверждение, что практический предел размера файла базы данных составляет несколько десятков ГБ: с. В основном это было связано с необходимостью SQLite «выделять битые карты грязных страниц» при каждом запуске транзакции. Таким образом, 256 байт оперативной памяти требовалось для каждого МБ в базе данных. Вставка в DB-файл объемом 50 ГБ потребует огромного (2 ^ 8) * (2 ^ 10) = 2 ^ 18 = 256 МБ ОЗУ.

Но с недавних версий SQLite это больше не требуется. Узнайте больше здесь .

Аликс Аксель
источник
25
Мне очень жаль, что я должен указать на это, но 2^18на самом деле это всего лишь 256 К.
Габриэль Шрайбер
7
@GabrielSchreiber, а также тот факт, что 50 ГБ это не (2 ^ 10) МБ, это только 1 ГБ. Таким образом, для базы данных объемом 50 ГБ вам нужно 12,5 МБ памяти: (2 ^ 8) * (2 ^ 10) * 50
elipoultorak
8

У меня возникли проблемы с большими файлами sqlite при использовании команды вакуума.

Я еще не пробовал функцию auto_vacuum. Если вы планируете часто обновлять и удалять данные, на это стоит обратить внимание.

eodonohoe
источник