2009-03-18 6 views
50

Sto provando a caricare in massa un sacco di dati (5,5 milioni di righe) in un file di database SQLite. Il caricamento tramite INSERT sembra essere troppo lento, quindi sto provando a utilizzare lo strumento da riga di comando sqlite3 e il comando .import.Come automatizzare un processo con lo strumento da riga di comando sqlite3.exe?

Funziona perfettamente se inserisco i comandi a mano, ma non riesco per la vita di me a capire come automatizzarlo da uno script (file .bat o script python; Sto lavorando su una macchina Windows).

I comandi ho problema nella riga di comando sono i seguenti:

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

Ma niente provo avranno questo lavoro da un file bat o uno script python.

ho cercato le cose come:

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

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

Sicuramente posso fare questo in qualche modo?

+0

Quanto lento è il caricamento tramite INSERT? Inserisco 15 milioni di righe di grandi dimensioni in Sqlite in 12 minuti con istruzioni di inserimento. Devi usare le transazioni e le dichiarazioni preparate. – tuinstoel

+0

Molto lento. Sto usando python per analizzare un file di log e inserire ogni riga come una riga. Non sto usando dichiarazioni preparate, ma sto usando le transazioni. Anche così è molto più veloce farlo utilizzando il programma sqlite3. – dave

+0

L'uso di istruzioni preparate fa una grande differenza. Posso creare un database sqlite da due gigabyte (1 grande tavolo con 1 indice) in 12 minuti con INSERT su un PC standard. – tuinstoel

risposta

47

Creare un file di testo con le linee che si desidera inserire nel programma da riga di comando SQLite, in questo modo:

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

e poi basta chiamare sqlite3 database.db < commands.txt

+0

La soluzione è corretta così com'è, mi sono bloccato perché non è possibile avere spazi prima di un punto. comando nel tuo script. FYI – ozmike

15

Creare un file di testo separato che contiene tutti i comandi che normalmente digitare in app shell sqlite3:

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

Salva come, ad esempio, impscript.sql.

creare un file batch che chiama il guscio sqlite3 con lo script:

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

chiamare il file batch.

Nota a margine: quando si importa, assicurarsi di avvolgere gli INSERT in una transazione! Ciò ti darà un aumento istantaneo 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 

ma la sua impossibile scrivere come come hai scritto

+1

La chiamata ".separator", "" non ha alcun effetto quando si eseguono più processi sqlite, come indicato sopra. –

+0

Grazie mille per aver fornito queste informazioni – Bhargava

23

In alternativa si può mettere tutto in un unico file di script di shell (semplificando così la manutenzione) utilizzando heredocimport.sh:

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

... ed eseguilo:

import.sh database.db 

Semplifica la manutenzione di un solo file di script. A proposito, se è necessario eseguirlo sotto Windows, Power Shell also features heredoc

Inoltre questo approccio aiuta a gestire il mancato supporto dei parametri di script.È possibile utilizzare variabili 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 anche fare un trucco del genere:

#!/bin/bash -- 

table_name=$2 

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

... ed eseguirlo: import.sh database.db log_entry

+0

L'autore - menziona che sta lavorando su Windows -FYI – ozmike

5

Ho da poco avuto un problema simile durante la conversione Firefox 'cookies.sqlite in un file di testo (per alcuni strumenti di download) e si è imbattuto in questa domanda.

volevo farlo con una singola linea di shell e che sarebbe la mia soluzione applicata al problema di cui sopra:

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

Ma non ho ancora testato quella linea. Ma ha funzionato bene con il problema di Firefox che ho citato sopra (btw via Bash su Mac OSX):

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

Posso confermare che questo metodo funziona; l'ho provato su OSX senza problemi. –

+1

L'autore - menziona che sta lavorando su Windows -FYI – ozmike

+0

Non esiste un comando come'echo -e 'sotto windows. Come già commentato da ozmike, l'autore dice "Sto lavorando su una macchina Windows". – PeterCo

1

A questo punto, io non sono sicuro che altro posso aggiungere altro che, ho avuto qualche difficoltà ad aggiungere un Unix variabile di ambiente per lo script di bash suggerito da nad2000.

l'esecuzione di questo:

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

avevo bisogno di importare da stdin come soluzione alternativa e ho trovato questa soluzione:

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

Aggiungendo la seconda linea sqlite3, sono stato in grado di superare i $ 2 da Unix nel parametro file per .import, percorso completo e tutto.

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

Benvenuti in Stack Overflow! Sebbene questo snippet di codice possa risolvere la domanda, inclusa una spiegazione [aiuta davvero] (// meta.stackexchange.com/q/114762) per migliorare la qualità del tuo post. Ricorda che stai rispondendo alla domanda per i lettori in futuro, non solo la persona che chiede ora! Si prega di [modificare] la risposta per aggiungere una spiegazione e fornire un'indicazione di quali limitazioni e ipotesi si applicano. –

0

In Windows, questo dovrebbe funzionare:

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

non ho ancora testato questo comando particolare, ma dalla mia ricerca di risolvere questo problema di tubazioni comandi multipli ho scoperto che la chiave è stato quello di racchiudere i comandi eco tra parentesi. Detto questo, è possibile che potrebbe essere necessario modificare il comando sopra per sfuggire anche a qualcuno di quei personaggi. Per esempio:

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

non sono sicuro se è necessaria la fuga in questo caso, ma è altamente probabile dal momento che le parentesi possono entrare in conflitto con quelli che racchiudono, poi il "meno di" e "superiore a "i simboli sono solitamente interpretati come input o output che possono anche essere in conflitto. Un elenco completo di escape dei personaggi può essere trovato qui: http://www.robvanderwoude.com/escapechars.php