2009-03-18 11 views
50

Estoy tratando de cargar a granel una gran cantidad de datos (5.5 millones de filas) en un archivo de base de datos SQLite. La carga a través de INSERT parece ser demasiado lenta, así que estoy tratando de usar la herramienta de línea de comandos sqlite3 y el comando .import.¿Cómo automatizar un proceso con la herramienta de línea de comandos sqlite3.exe?

Funciona a la perfección si ingreso los comandos a mano, pero no puedo por la forma de automatizarlo desde un script (archivo .bat o script de python; estoy trabajando en una máquina con Windows)

Los comandos que tema en la línea de comandos son los siguientes:

> sqlite3 database.db 
sqlite> CREATE TABLE log_entry (<snip>); 
sqlite> .separator "\t" 
sqlite> .import logfile.log log_entry 

Pero nada se trato conseguir que esto funcione desde un archivo de murciélago o script en Python.

He estado tratando de cosas como:

sqlite3 "database.db" .separator "\t" .import logfile.log log_entry 

echo '.separator "\t" .import logfile.log log_entry' | sqlite3 database.db 

Seguramente me puede hacer esto de alguna manera?

+0

¿Qué tan lenta es su carga a través de INSERT? Inserté 15 millones de filas grandes en Sqlite en 12 minutos con instrucciones de inserción. Debe usar transacciones y declaraciones preparadas. – tuinstoel

+0

Muy lento. Estoy usando python para analizar un archivo de registro e insertar cada línea como una fila. No estoy usando declaraciones preparadas, pero estoy usando transacciones. Aún así, es mucho más rápido hacer esto usando el programa sqlite3. – dave

+0

Usar declaraciones preparadas hace una diferencia descomunal. Puedo crear una base de datos sqlite de dos gigabytes (1 gran tabla con 1 índice) en 12 minutos con INSERT en una PC estándar. – tuinstoel

Respuesta

47

Crear un archivo de texto con las líneas que desea entrar en el programa de línea de comandos sqlite, así:

 
CREATE TABLE log_entry (); 
.separator "\t" 
.import logfile.log log_entry

y luego a llamarlo sqlite3 database.db < commands.txt

+0

Tu solución es correcta como es, me quedé atascado ya que no puedes tener espacios antes de un punto. comando en su secuencia de comandos. FYI – ozmike

15

Crear un archivo de texto separado que contiene todos los comandos que normalmente se escribe en la aplicación de shell sqlite3:

CREATE TABLE log_entry (<snip>); 
.separator "\t" 
.import /path/to/logfile.log log_entry 

Guardar como, por ejemplo, impscript.sql.

Crear un archivo por lotes que llama a la cáscara de sqlite3 con ese guión:

sqlite3.exe yourdatabase.db < /path/to/impscript.sql 

llamada el archivo por lotes.

En una nota al margen - al importar, asegúrese de envolver los INSERT en una transacción! Eso te dará una aceleración instantánea del 10.000%.

-1
here trans is table name and trans.csv is a csv file in which i have 1959 rows of data 

    $ sqlite3 abc.db ".separator ','" 
    $ sqlite3 abc.db ".import 'trans.csv' trans" 
    $ sqlite3 abc.db "select count(*) from trans;" 
    1959 

pero es imposible escribir como lo que escribió

+1

Llamar ".separator ','" no tiene ningún efecto cuando ejecuta varios procesos sqlite, como ha indicado anteriormente. –

+0

Muchas gracias por dar esta información – Bhargava

23

Alternativamente se puede poner todo en un archivo script de shell (simplificando así el mantenimiento) utilizando heredocimport.sh:

#!/bin/bash -- 
sqlite3 -batch $1 <<"EOF" 
CREATE TABLE log_entry (<snip>); 
.separator "\t" 
.import logfile.log log_entry 
EOF 

... y ejecutarlo:

import.sh database.db 

Hace que sea más fácil mantener solo un archivo de script. Por cierto, si necesita ejecutarlo en Windows, Power Shell also features heredoc

Además, este enfoque ayuda a lidiar con la falta de soporte de parámetros de script.Puede utilizar variables bash:

#!/bin/bash -- 

table_name=log_entry 

sqlite3 -batch $1 <<EOF 
CREATE TABLE ${table_name} (<snip>); 
.separator "\t" 
.import logfile.log ${table_name} 
EOF 

O incluso hacer un truco como esto:

#!/bin/bash -- 

table_name=$2 

sqlite3 -batch $1 <<EOF 
CREATE TABLE ${table_name} (<snip>); 
.separator "\t" 
.import logfile.log ${table_name} 
EOF 

... y ejecutarlo: import.sh database.db log_entry

+0

El autor - menciona que está trabajando en una ventana -FYI – ozmike

5

Hace poco tuve un problema similar al convertir Firefox 'cookies.sqlite' a un archivo de texto (para alguna herramienta de descarga) y tropezó con esta pregunta.

que quería hacer eso con una sola línea de concha y que sería mi solución aplicada al problema mencionado anteriormente:

echo -e ".mode tabs\n.import logfile.log log_entry" | sqlite3 database.db 

Pero no he probado esa línea todavía. Pero funcionó bien con el problema de Firefox que he mencionado anteriormente (por cierto a través de Bash en Mac OS X):

echo -e ".mode tabs\nselect host, case when host glob '.*' then 'TRUE' else 'FALSE' end, path, case when isSecure then 'TRUE' else 'FALSE' end, expiry, name, value from moz_cookies;" | sqlite3 cookies.sqlite 
+0

Puedo confirmar que este método funciona; Acabo de probarlo en OSX sin ningún problema. –

+1

El autor menciona que está trabajando en una ventana -FYI – ozmike

+0

No existe un comando como'echo -e' debajo de windows. Como ozmike ya comentó, el autor dice "Estoy trabajando en una máquina con Windows". – PeterCo

1

En este punto, no estoy seguro de qué más puedo añadir aparte, tuve algunos problemas para añadir una variable de entorno unix para el script bash sugerido por nad2000.

ejecutar este:

bash dbmake.sh database.db <(sed '1d' $DATA/logfile.log | head -n 1000) 

que necesitaba para importar de la entrada estándar como solución y me encontré con esta solución:

sqlite3 $1 <<"EOF" 
CREATE TABLE log_entry; 
EOF 
sqlite3 -separator $'\t' $1 ".import $2 log_entry" 

Mediante la adición de la segunda línea sqlite3, yo era capaz de pasar los $ 2 a partir de Unix en el parámetro de archivo para .import, ruta completa y todo.

2
sqlite3 abc.db ".read scriptname.sql" 
+2

¡Bienvenido a Stack Overflow! Si bien este fragmento de código puede resolver la pregunta, incluye una explicación [realmente ayuda] (// meta.stackexchange.com/q/114762) para mejorar la calidad de su publicación. Recuerde que usted está respondiendo la pregunta a los lectores en el futuro, ¡no solo a la persona que pregunta ahora! Por favor [edite] su respuesta para agregar una explicación y dar una indicación de qué limitaciones y suposiciones se aplican. –

0

En Windows, esto debería funcionar:

(echo CREATE TABLE log_entry (<snip>); & echo .separator "\t" & echo .import logfile.log log_entry) | sqlite3.exe database.db 

No he probado este comando en particular, sino de mi propia búsqueda de la solución de este problema de tuberías múltiples comandos descubrí que la clave era para encerrar los comandos repetidos entre paréntesis. Dicho esto, es posible que necesite modificar el comando anterior para también escapar de algunos de esos caracteres. Por ejemplo:

(echo CREATE TABLE log_entry ^(^<snip^> ^); & echo .separator "\t" & echo .import logfile.log log_entry) | sqlite3.exe database.db 

No estoy seguro de si se necesita la escapatoria en este caso, pero es muy probable ya que los paréntesis pueden entrar en conflicto con los que encierran, entonces el "menos de" y "mayor que "los símbolos generalmente se interpretan como entrada o salida que también pueden entrar en conflicto. Puede encontrar una extensa lista de escape de caracteres aquí: http://www.robvanderwoude.com/escapechars.php

Cuestiones relacionadas