las inserciones más rápidas en sqlite3?
Pregunta
Tengo un archivo de alrededor de 30.000 líneas de datos que desea cargar en una base de datos sqlite3. ¿Hay una manera más rápida que la generación de instrucciones de inserción para cada línea de datos?
Los datos están separados por espacio y asigna directamente a una tabla sqlite3. ¿Hay algún tipo de método de inserción masiva para añadir los datos de volumen a una base de datos?
¿Alguien ha ideado alguna manera sinuosamente maravillosa de hacer esto si no está construido en?
Debería aclarar esto preguntando, ¿hay una manera de C ++ que hacerlo desde la API?
Solución
También puede intentar ajustar algunos parámetros para conseguir velocidad extra fuera de ella. Específicamente es probable que desee PRAGMA synchronous = OFF;
.
Otros consejos
- envolver todos los insertos en una transacción, incluso si hay un solo usuario, que es mucho más rápido.
- usar comandos preparados.
Usted desea utilizar el comando .import
. Por ejemplo:
$ 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
Tenga en cuenta que este comando de carga a granel no es SQL sino más bien una función personalizada de SQLite. Como tal, tiene una sintaxis extraña, porque estamos pasándola a través de echo
al intérprete de línea de comandos interactiva, sqlite3
.
En PostgreSQL el equivalente es COPY FROM
:
http://www.postgresql.org/docs/8.1/static/sql -copy.html
En MySQL es LOAD DATA LOCAL INFILE
:
http://dev.mysql.com/doc/refman/5.1 /en/load-data.html
Una última cosa: recuerde que debe tener cuidado con el valor de .separator
. Esa es una de gotcha muy común al hacer las inserciones.
sqlite> .show .separator
echo: off
explain: off
headers: on
mode: list
nullvalue: ""
output: stdout
separator: "\t"
width:
Es necesario configurar explícitamente el separador de ser un espacio, ficha, o una coma antes de hacer <=>.
-
Aumentar
PRAGMA default_cache_size
a un número mucho mayor. Esta voluntad aumentar el número de páginas en caché en la memoria. -
Envuelva todas las inserciones en una sola transacción en lugar de una transacción por fila.
- Use compilado de sentencias SQL para hacer las inserciones.
- Por último, como ya se ha mencionado, si usted está dispuesto renunciar cumplimiento ÁCIDO total, ajuste
PRAGMA synchronous = OFF;
.
RE: "¿Hay una manera más rápida que la generación de instrucciones de inserción para cada línea de datos"
Primero: Córtala a 2 sentencias SQL, haciendo uso de API de tabla virtual de Sqlite3 ejemplo,
create virtual table vtYourDataset using yourModule;
-- Bulk insert
insert into yourTargetTable (x, y, z)
select x, y, z from vtYourDataset;
La idea aquí es que implemente una interfaz C que establecen lee los datos de origen y presentarlo a SQLite como una tabla virtual y luego hacer una copia de SQL desde la fuente a la tabla de destino de una sola vez. Suena difícil de lo que realmente es y lo he medido enormes mejoras en la velocidad de esta manera.
Segundo: Hacer uso de otro consejo aquí proporcionada es decir, la configuración pragma y haciendo uso de una transacción
.En tercer lugar: Tal vez ver si se puede acabar con algunos de los índices de la tabla de destino. De esa manera sqlite tendrá menos índices de actualización para cada fila insertada
No hay manera de inserción masiva, pero hay una manera de escribir trozos grandes a la memoria, a continuación, las aprenden de la base de datos. Para la API de C / C ++, acaba de hacer:
sqlite3_exec (db, "BEGIN TRANSACTION", NULL, NULL, NULL);
... (instrucciones INSERT)
sqlite3_exec (db, "COMMIT TRANSACTION", NULL, NULL, NULL);
Suponiendo db es el puntero de su base de datos.
Un buen compromiso es envolver su inserta entre COMENZAR; y punto; es decir palabra clave:
BEGIN;
INSERT INTO table VALUES ();
INSERT INTO table VALUES ();
...
END;
En función del tamaño de los datos y la cantidad de memoria RAM disponible, uno de ocurrirán mediante el establecimiento de SQLite a utilizar una base de datos todo en la memoria en lugar de escribir en el disco las mejores mejoras de rendimiento.
Para bases de datos, pasan a NULL como el argumento de nombre de archivo para sqlite3_open
en memoria y asegurarse que TEMP_STORE se define apropiadamente
(Todo el texto anterior es un extracto de mi propia respuesta a una sqlite- separada relacionada pregunta )
Me pareció que para ser una buena mezcla para una larga importación de un disparo.
.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
Fuente: http: //erictheturtle.blogspot. ser / 2009/05 / más rápido de importación masiva-en-sqlite.html
algo de información adicional: http: //blog.quibb .org / 2010/08 / fast-bulk-inserciones-en-sqlite /
Si se acaba de insertar una vez, es posible que tenga un truco sucio por ti.
La idea es simple, primero insertar en una base de datos de memoria, a continuación, copia de seguridad y restaurar finalmente a su archivo de base de datos original.
he escrito los pasos detallados en mi el blog . :)