Удаление SQLITE занимает очень много времени - PullRequest
0 голосов
/ 18 июня 2020

У меня есть таблица, которая выглядит так:

CREATE TABLE records (
    batchID TEXT,
    A       TEXT,
    A_id    REAL,
    B       TEXT,
    B_id    REAL,
    C       REAL,
    D       REAL,
    E       REAL,
    F       REAL,
    G       REAL,
    H       REAL,
    color   REAL,
    repair  REAL,
    data    BLOB,
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT
)

У меня есть индекс таблицы по некоторым столбцам. Поскольку целостность не является проблемой, у меня есть:

PRAGMA synchronous = "0"
PRAGMA journal_mode = "OFF"

В db часто вставляются, у меня около 2 миллионов строк в моей таблице записей, а размер файла db составляет ~ 2 ГБ. Раз в несколько часов мне нужно удалить 200К строк из таблицы записей. Я использую node js orm:

db.driver.execQuery('DELETE FROM records WHERE A IN ? AND batchID = ?',
    [['a1', 'a2'], 'batch123'],
    function(err) {
    // do stuff here    
    });

Вначале удаление занимает около 10 секунд, однако после месяца работы оператор удаления может занять более часа (!) (См. Прилагаемый график производительности из журналов, где я регистрирую время удаления - оранжевые кружки, синие кружки - память узла). Это проблема, поскольку во время удаления в node генерируются новые запросы на запись. Эти запросы на запись помещаются в очередь в памяти, чтобы точечный узел использовал огромный объем памяти. (поскольку удаление блокирует таблицу и блокирует запись)

Я подозреваю, что это связано с тем, что база данных становится фрагментированной. Вакуум для меня не вариант, так как это продукт, который нельзя остановить, и когда я тестировал время вакуумирования на копии файла sqlite db, это заняло 15-30 минут. Автоматический вакуум, насколько я понимаю, не поможет, поскольку он не сжимает данные на страницах и может ухудшить фрагментацию. Еще я пытался установить размер страницы 4096, это тоже не помогло. график производительности

1 Ответ

0 голосов
/ 19 июня 2020

По умолчанию вставка или удаление SQLite выполняется в неявной транзакции, что снижает скорость.

From https://www.sqlite.org/lang_transaction.html:

транзакция чтения запускается оператором SELECT, а транзакция записи запускается такими операторами, как CREATE, DELETE, DROP, INSERT или UPDATE (вместе «операторы записи»).

Из FAQ 19 https://www.sqlite.org/faq.html:

INSERT работает очень медленно - я могу делать только несколько десятков INSERT в секунду

По умолчанию каждая инструкция INSERT является отдельной транзакцией. Но если вы заключите несколько операторов INSERT в окружение BEGIN ... COMMIT, тогда все вставки будут сгруппированы в одну транзакцию. Время, необходимое для фиксации транзакции, амортизируется по всем вложенным инструкциям вставки, поэтому время на инструкцию вставки значительно сокращается.

EDIT: вопрос изменился после того, как я написал этот ответ, поэтому он может кажется бессмысленным.

Обычно вы не должны использовать AUTOINCREMENT с SQLite, он не нужен и отрицательно влияет на производительность, см. https://sqlite.org/autoinc.html:

Ключевое слово AUTOINCREMENT накладывает дополнительные расходы на ЦП, память, дисковое пространство и дисковый ввод-вывод, и его следует избегать, если это не является строго необходимым. Обычно это не требуется.

В SQLite столбец с типом INTEGER PRIMARY KEY является псевдонимом для ROWID (кроме таблиц WITHOUT ROWID), который всегда является 64-битным целым числом со знаком.

В случае INSERT, если столбцу ROWID или INTEGER PRIMARY KEY явно не присвоено значение, то он будет автоматически заполнен неиспользуемым целым числом, обычно на единицу больше, чем самый большой ROWID, используемый в настоящее время. Это верно независимо от того, используется ли ключевое слово AUTOINCREMENT.

Если ключевое слово AUTOINCREMENT появляется после INTEGER PRIMARY KEY, это изменяет алгоритм автоматического назначения c ROWID, чтобы предотвратить повторное использование ROWID в течение срока службы база данных. Другими словами, цель AUTOINCREMENT - предотвратить повторное использование ROWID из ранее удаленных строк.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...