Более быстрые массовые вставки в sqlite3?

У меня есть файл около 30000 строк данных, которые я хочу загрузить в базе данных sqlite3. Есть ли более быстрый способ, чем генерирование инструкций insert для каждой строки данных?

данные разделены пробелами и сопоставляются непосредственно с таблицей sqlite3. Существует ли какой-либо метод массовой вставки для добавления данных Тома в базу данных?

кто-нибудь изобрел какой-то дьявольски замечательный способ сделать это, если он не встроен?

Я должен предварить это вопросом: есть способ C++ сделать это из API?

10 ответов


вы также можете попробовать настройки нескольких параметров чтобы получить дополнительную скорость из нее. В частности, вы, вероятно, хотите PRAGMA synchronous = OFF;.


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

вы хотите использовать . Например:

$ cat demotab.txt
44      92
35      94
43      94
195     49
66      28
135     93
135     91
67      84
135     94

$ echo "create table mytable (col1 int, col2 int);" | sqlite3 foo.sqlite
$ echo ".import demotab.txt mytable"  | sqlite3 foo.sqlite

$ sqlite3 foo.sqlite
-- Loading resources from /Users/ramanujan/.sqliterc
SQLite version 3.6.6.2
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> select * from mytable;
col1    col2
44      92
35      94
43      94
195     49
66      28
135     93
135     91
67      84
135     94

обратите внимание, что эта команда массовой загрузки не является SQL, а скорее пользовательской функцией SQLite. Таким образом, он имеет странный синтаксис, потому что мы передаем его через echo в интерактивный интерпретатор командной строки sqlite3.

в PostgreSQL эквивалент COPY FROM: http://www.postgresql.org/docs/8.1/static/sql-copy.html

в MySQL это LOAD DATA LOCAL INFILE: http://dev.mysql.com/doc/refman/5.1/en/load-data.html

последнее: помните, что нужно быть осторожным со значением .separator. Это очень распространенный gotcha при выполнении объемных вставок.

sqlite> .show .separator
     echo: off
  explain: off
  headers: on
     mode: list
nullvalue: ""
   output: stdout
separator: "\t"
    width:

вы должны явно установить разделитель как пробел, вкладку или запятую перед выполнением .import.


  • увеличить PRAGMA default_cache_size к гораздо большему числу. Эта воля увеличение количества кэшированных страниц в памяти.

  • оберните все вставки в одну транзакцию, а не одну транзакцию на строку.

  • используйте скомпилированные операторы SQL для выполнения вставок.
  • наконец, как уже упоминалось, если вы готовы отказаться от полного соответствия кислоты, установите PRAGMA synchronous = OFF;.

RE: "есть ли более быстрый способ генерации инструкций insert для каждой строки данных?"

во-первых: сократите его до 2 операторов SQL, используя sqlite3 API виртуальной таблицы например

create virtual table vtYourDataset using yourModule;
-- Bulk insert
insert into yourTargetTable (x, y, z)
select x, y, z from vtYourDataset;

идея здесь заключается в том, что вы реализуете интерфейс C, который читает ваш исходный набор данных и представляет его SQlite как виртуальную таблицу, а затем вы делаете копию SQL из источника в целевую таблицу за один раз. Это звучит сложнее, чем на самом деле. это и я измерил огромные улучшения скорости таким образом.

Second: используйте другой совет, представленный здесь, т. е. настройки pragma и использование транзакции.

В-третьих: возможно, вы можете избавиться от некоторых индексов в целевой таблице. Таким образом, sqlite будет иметь меньше индексов для обновления для каждой вставленной строки


нет способа массовой вставки, но существует способ писать большие куски к памяти, после этого поручите их к база данных. Для API C / C++ просто выполните:

sqlite3_exec(db, " начать транзакцию", NULL, NULL, NULL);

...(Вставить заявления)

sqlite3_exec(db, "COMMIT TRANSACTION", NULL, NULL, NULL);

предполагая, что db является указателем базы данных.


хорошим компромиссом является обертывание вставок между BEGIN; и END; ключевое слово i.e:

BEGIN;
INSERT INTO table VALUES ();
INSERT INTO table VALUES ();
...
END;

в зависимости от размера данных и объема доступной оперативной памяти, один из лучших прирост производительности произойдет путем установки sqlite использовать базу данных все-в-памяти, а не записи на диск.

для баз данных в памяти передайте NULL в качестве аргумента filename в sqlite3_open и убедитесь, что TEMP_STORE определен соответствующим образом

(весь вышеприведенный текст взят из моего собственного ответа на отдельный вопрос, связанный с sqlite)


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

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

Я написал подробные шаги в мой блог. :)


Я нашел, что это хорошее сочетание для импорта с одним выстрелом.

.echo ON

.read create_table_without_pk.sql

PRAGMA cache_size = 400000; PRAGMA synchronous = OFF; PRAGMA journal_mode = OFF; PRAGMA locking_mode = EXCLUSIVE; PRAGMA count_changes = OFF; PRAGMA temp_store = MEMORY; PRAGMA auto_vacuum = NONE;

.separator "\t" .import a_tab_seprated_table.txt mytable

BEGIN; .read add_indexes.sql COMMIT;

.exit

источник: http://erictheturtle.blogspot.be/2009/05/fastest-bulk-import-into-sqlite.html

дополнительная информация:http://blog.quibb.org/2010/08/fast-bulk-inserts-into-sqlite/