Які характеристики продуктивності sqlite з дуже великими файлами баз даних? [зачинено]


325

Я знаю, що sqlite не дуже добре працює з надзвичайно великими файлами баз даних, навіть коли вони підтримуються (раніше на сайті sqlite був коментар, який стверджує, що якщо вам потрібні розміри файлів вище 1 Гб, ви можете розглянути можливість використання корпоративних rdbms. Можна Ви не знайдете його більше, можливо, це стосується старішої версії sqlite).

Однак для своїх цілей я хотів би зрозуміти, наскільки це насправді погано, перш ніж розглянути інші рішення.

Я говорю про файли даних sqlite в багатогігабайтному діапазоні, починаючи від 2 Гб. Хтось має з цим досвід? Якісь поради / ідеї?


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 оптимізувати файл та відновити файловий простір.

Однак, як зазначається в документації , повна копія бази даних робиться, щоб зробити вакуум, для того щоб зайняти дуже багато часу. Отже, чим менша база даних, тим швидше ця операція закінчиться.

Висновки

У моєму конкретному застосуванні я, мабуть, буду розбивати дані на кілька db-файлів, один на день, щоб отримати найкращу ефективність роботи вакууму та швидкість вставки / видалення.

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

Ймовірно, мені слід було б також відстежувати розмір таблиці на файл, щоб побачити, коли швидкість стане проблемою.

Це дуже погано, що, здається, не існує інкрементального методу вакууму, крім автоматичного вакууму . Я не можу його використовувати, тому що моя мета вакууму - дефрагментація файлу (файловий простір не є великою справою), що не робить автоматичний вакуум. Насправді в документації зазначено, що це може погіршити фрагментацію, тому мені доводиться періодично вдаватися до повного вакуумування файлу.


5
Дуже корисна інформація. Чисті міркування, але мені цікаво, чи можна використовувати новий резервний файл api для створення не фрагментованої версії вашої бази даних щодня, і уникати необхідності запускати VACUUM.
eodonohoe

24
Мені цікаво, чи були всі ваші ВСТУПИ в транзакції?
Пол Лефевр

9
Так, вставки проводилися партіями по 10000 повідомлень за транзакцію.
Snazzer

6
Якою файловою системою ви користувалися? Якщо ext {2,3,4}, що було встановлено для даних = налаштування, чи було ввімкнено журнал? Крім шаблонів io, спосіб передачі 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;

Сподіваюся, що це допоможе іншим, тут чудово працює


22
Нещодавно протестований з dbs в діапазоні 160 ГБ, також чудово працює.
Snazzer

10
Також PRAGMA main.temp_store = MEMORY;.
Вікрант Чадхарі

40
@ Алекс, чому є два PRAGMA main.cache_size = 5000 ;?
Джек

23
Не просто сліпо застосовуйте ці оптимізації. Зокрема синхронний = NORMAL не є безпечним для аварій. Тобто збої процесу в потрібний час можуть пошкодити вашу базу даних навіть за відсутності збоїв на диску. sqlite.org/pragma.html#pragma_synchronous
mpm

22
@ Алекс, чи можете ви пояснити ці значення та різницю між тими та типовими?
4m1nh4j1

65

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

Відповідно до сторінки SQLite Limits , максимальний розмір кожної сторінки бази даних - 32K. А максимальна кількість сторінок у базі даних - 1024 ^ 3. Тож за моєю математикою, яка виходить на 32 терабайта як максимальний розмір. Я думаю, ви досягнете меж вашої файлової системи, перш ніж потрапляти на SQLite!


3
Залежно від того, які операції ви виконуєте, намагаючись видалити 3000 рядків у базі даних 8G sqlite, вам потрібно достатньо часу, щоб заварити гарний горщик французької преси, lol
Бенджамінц

4
@benjaminz, ти мусиш робити це неправильно. Якщо ви завершите видалення 3k рядків за одну транзакцію, це повинно бути майже миттєвим. У мене була така помилка: видалення 10k рядків один за одним зайняло 30 хв. Але як тільки я завернув усі операції видалення в одну транзакцію, це пройшло 5 секунд.
mvp

55

Більшість причин, через які знадобилось> 48 годин, щоб зробити свої вставки, - це через ваші індекси. Це неймовірно швидше:

1 - Відкинути всі індекси 2 - Зробити всі вставки 3 - Створити індекси заново


23
Це добре відомо ... але для тривалого запущеного процесу ви не збираєтесь періодично скидати свої індекси, щоб відновити їх, особливо коли ви збираєтесь запитувати їх у виконанні роботи. Такий підхід застосовується, хоча, коли sqlite db має бути відновлено з нуля, індекси створюються після того, як будуть виконані всі вставки.
Snazzer

24
@Snazzer у подібній ситуації ми використовували таблицю «акумулятор»: раз на день ми переміщуватимемо накопичені рядки з таблиці акумулятора до основної таблиці в рамках однієї транзакції. Там, де потрібно, переглядав подання обох таблиць як єдину таблицю.
CAFxX

4
Інший варіант - зберегти індекси, але попередньо впорядкуйте дані у порядку індексу, перш ніж вставляти їх.
Стівен Крискалла

1
@StevenKryskalla як це порівняти зі скиданням індексів та їх відтворенням? Будь-які посилання, які ви знаєте про це, орієнтувались?
mcmillab

1
@mcmillab Це було років тому, тому я не пам’ятаю всіх деталей чи статистичних показників, але інтуїтивно роздумуючи, вставлення N випадково упорядкованих елементів у індекс забирає час O (NlogN), тоді як вставлення N відсортованих елементів займе O (N ) час.
Стівен Крискалла

34

Крім звичайної рекомендації:

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

З досвіду роботи з SQLite3 я дізнався наступне:

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

Питання / коментар Ласкаво просимо. ;-)


1
Скільки впливу ви отримуєте від "однієї таблиці на db-файл"? Звучить цікаво. Як ви вважаєте, це мало б значення, якщо ваш стіл має лише 3 таблиці та будується з нуля?
Мартін Велес

4
@martin ненавидить це говорити, але відповідь залежить . Ідея полягає в розподілі даних на керований розмір. У моєму випадку я збираю дані від різних хостів і звітуюсь про них після факту, щоб цей підхід спрацював добре. Розділ за датою / часом, як пропонують інші, повинен добре працювати для даних, які тривалий проміжок часу я б міг собі уявити.
Лестер Чеун

3
@Lester Cheung: Що стосується вашого другого №1: Я розумію з документів і особистого досвіду, що до сьогодні SQLite3 не підтримує додавання обмежень ALTER TABLE після створення таблиці. Єдиний спосіб додати або видалити обмеження з існуючих рядків таблиці - це створити нову таблицю з потрібними характеристиками та скопіювати всі рядки, що, ймовірно, буде набагато повільніше, ніж вставити один раз із обмеженнями.
Буркунки

3
@Widdershins ви абсолютно праві - ALTER TABLE в SQLite не дозволяє додавати обмеження. Я не знаю, що я курив - оновлю відповідь - дякую.
Лестер Чеун

Жодна з цих пропозицій не має нічого спільного з використанням humongous db-файлів SQLite. Чи було питання відредаговане з моменту подання цієї відповіді?
А.Рагер

9

Я думаю, що основні скарги на масштабування sqlite:

  1. Один процес запису.
  2. Без дзеркального відображення
  3. Немає реплікації.

9

У мене база даних SQLite 7 Гб. Для виконання конкретного запиту з внутрішнім з'єднанням потрібні 2.6 секунди. Щоб прискорити це, я спробував додати індекси. Залежно від того, який індекс я додав, іноді запит знижувався до 0,1s, а іноді - до 7s. Я думаю, що проблема в моєму випадку полягала в тому, що якщо стовпець сильно повторюється, то додавання індексу знижує продуктивність :(


9
Чому стовпець з багатьма дублікатами погіршує продуктивність (серйозне питання)?
Мартін Велес

6
стовпець з низькою потужності важче індекс: stackoverflow.com/questions/2113181 / ...
Metrix

9

У документації на SQLite раніше було твердження, що обмеження практичного розміру файлу бази даних становить кілька десятків ГБ: с. Здебільшого це було пов'язано з необхідністю SQLite "виділяти растрову карту брудних сторінок" кожного разу, коли ви розпочали транзакцію. Таким чином, потрібно було 256 байт оперативної пам’яті для кожного МБ в базі даних. Щоб вставити в 50 ГБ DB-файл, потрібно значне (2 ^ 8) * (2 ^ 10) = 2 ^ 18 = 256 Мб оперативної пам’яті.

Але що стосується останніх версій SQLite, це більше не потрібно. Детальніше читайте тут .


25
Мені дуже шкода, що я маю це зазначити, але 2^18насправді лише 256 К.
Габріель Шрайбер

7
@GabrielSchreiber, а також той факт, що 50GB не є (2 ^ 10) MB, це лише 1GB. Отже, для бази даних 50 Гб вам потрібно 12,5 МБ пам’яті: (2 ^ 8) * (2 ^ 10) * 50
elipoultorak

8

У мене виникли проблеми з великими файлами sqlite під час використання вакуумної команди.

Я ще не пробував функцію auto_vacuum. Якщо ви плануєте часто оновлювати та видаляти дані, то це варто переглянути.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.