Массовая вставка производительности в SQLite - PullRequest
0 голосов
/ 25 сентября 2019

В качестве упражнения я вижу, как быстро я могу вставлять массовые записи в SQLite.Набор данных составляет около 50 МБ и содержит 1 млн. Строк.Вот то, что у меня сейчас есть:

sqlite3 *db;
int rc = sqlite3_open("MyDB.db", &db);
sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, NULL);
char* sql_buffer = malloc(200 * sizeof(char));
for (int i=0; item=row[i]; i ++) {
    snprintf(sql_buffer, 200, "insert into myTable (id, format, size) VALUES (%d, '%s', %d)", item.id, item.format, item.size);
    rc = sqlite3_exec(db, sql_buffer, NULL, NULL, NULL);
}
sqlite3_exec(db, "COMMIT TRANSACTION", NULL, NULL, NULL);

При выполнении вышеупомянутых вставок 1M требуется 3.39s.Около 90% этого времени составляют вставки SQLite, а 10% - функция snprintf.Я попробовал следующее, чтобы увидеть, увеличит ли это скорость:

  • Делать вставки после каждых 10К, 50К, 100К, а не в конце (1М)
  • Запись в память вместофайл.
  • Изменение различных прагм, например: PRAGMA cache_size = 400000; PRAGMA synchronous = OFF; PRAGMA journal_mode = OFF; ...

Похоже, что ни один из них не имел эффекта больше, чем разница 0.1s илиитак.

Есть ли еще способы, которыми я мог бы увеличить скорость вставки здесь?Если мы предположим, что файл "проанализирован" и не может быть просто загружен непосредственно из чего-то вроде CSV-файла, теоретически возможно ли вставить 1M строк меньше 1 с?Если нет, то каково ограничение в выполнении чего-либо подобного?

1 Ответ

1 голос
/ 25 сентября 2019

Примите во внимание, что с вашим текущим подходом вставка 1 миллиона строк потребует выполнения 1 миллиона отдельных вставок туда и обратно в SQLite.Вместо этого вы можете попробовать использовать один из следующих двух подходов.Для более поздних версий SQLite:

INSERT INTO myTable (id, format, size)
VALUES
    (%d, '%s', %d),
    (%d, '%s', %d),
    (%d, '%s', %d),
    ... (more rows)

Для более ранних версий SQLite вы можете использовать конструкцию INSERT INTO ... SELECT:

INSERT INTO myTable (id, format, size)
SELECT %d, '%s', %d UNION ALL
SELECT %d, '%s', %d UNION ALL
... (more rows)

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

Не C-человек, но вот как вы можете построить строку вставки изВаш код C:

const int MAX_BUF = 1000;  // make this as large as is needed
char* sql_buffer = malloc(MAX_BUF * sizeof(char));
int length = 0;
length += snprintf(sql_buffer+length, MAX_BUF-length, "INSERT INTO myTable (id, format, size) VALUES");
for (int i=0; item=row[i]; i++) {
    length += snprintf(sql_buffer+length, MAX_BUF-length, " (%d, '%s', %d)", item.id, item.format, item.size);
}

rc = sqlite3_exec(db, sql_buffer, NULL, NULL, NULL);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...