web-dev-qa-db-fra.com

Comment automatiser un processus avec l'outil de ligne de commande sqlite3.exe?

J'essaie de charger en vrac beaucoup de données (5,5 millions de lignes) dans un fichier de base de données SQLite . Le chargement via INSERT semble être beaucoup trop lent, j'essaie donc d'utiliser l'outil de ligne de commande sqlite3 et le fichier. commande d'importation.

Cela fonctionne parfaitement si je saisis les commandes à la main, mais je ne peux pas me débrouiller toute seule pour savoir comment l’automatiser à partir d’un script (fichier .bat ou script python; je travaille sur une machine Windows).

Les commandes que j'émets sur la ligne de commande sont les suivantes:

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

Mais rien de ce que j'essaye ne fera fonctionner cela à partir d'un fichier bat ou d'un script python.

J'ai essayé des choses comme:

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

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

Sûrement je peux le faire en quelque sorte?

54
dave

Créez un fichier texte avec les lignes que vous souhaitez entrer dans le programme de ligne de commande sqlite, comme suit:

 CREATE TABLE log_entry (); 
. séparateur "\ t" 
. import logfile.log log_entry

puis appelez simplement sqlite3 database.db < commands.txt

51
Joey

Sinon, vous pouvez tout mettre dans un fichier de script Shell (simplifiant ainsi la maintenance) en utilisant heredocimport.sh:

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

... et lancez-le:

import.sh database.db

Cela facilite la maintenance d’un seul fichier de script ..__ Soit dit en passant, si vous avez besoin de l’exécuter sous Windows, Power Shell propose également heredoc

De plus, cette approche permet de remédier au manque de prise en charge des paramètres de script. Vous pouvez utiliser des 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

Ou même faire un tour comme ça:

#!/bin/bash --

table_name=$2

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

... et lancez-le: import.sh database.db log_entry

25
nad2000

Créez un fichier texte séparé contenant toutes les commandes que vous taperiez normalement dans l'application sqlite3 Shell:

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

Enregistrez-le sous, par exemple, impscript.sql.

Créez un fichier de commandes qui appelle le shell sqlite3 avec ce script:

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

Appelez le fichier de commandes.

Sur une note latérale - lors de l’importation, assurez-vous d’emballer les INSERTIONS dans une transaction ! Cela vous donnera une accélération instantanée de 10.000%.

17
Mihai Limbășan

J'ai récemment eu un problème similaire lors de la conversion de Firefox 'cookies.sqlite en fichier texte (pour certains outils de téléchargement) et suis tombé par hasard sur cette question.

Je voulais le faire avec une seule ligne Shell et ce serait ma solution appliquée au problème mentionné ci-dessus:

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

Mais je n'ai pas encore testé cette ligne. Mais cela a bien fonctionné avec le problème de Firefox mentionné plus haut (en passant par Bash sous 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
5
Pesthauch
sqlite3 abc.db ".read scriptname.sql"
2
someone

À ce stade, je ne suis pas sûr de ce que je peux ajouter, mais j'ai eu quelques problèmes pour ajouter une variable d'environnement Unix au script bash suggéré par nad2000.

en cours d'exécution ceci:

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

J'avais besoin d'importer de stdin comme solution de contournement et j'ai trouvé cette solution:

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

En ajoutant la deuxième ligne sqlite3, j'ai pu faire passer le $ 2 sous Unix dans le paramètre de fichier pour .import, le chemin complet et tout.

1
jimh

Sous Windows, cela devrait fonctionner:

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

Je n'ai pas testé cette commande particulière, mais dans le but de résoudre ce problème de canalisation de commandes multiples, j'ai constaté que la clé consistait à placer les commandes en écho entre parenthèses. Cela étant dit, il est possible que vous deviez peut-être modifier la commande ci-dessus pour échapper également à certains de ces caractères. Par exemple:

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

Je ne suis pas sûr que l'échappement soit nécessaire dans ce cas, mais il est fort probable que les parenthèses puissent entrer en conflit avec celles qui les entourent, les symboles "inférieur à" et "supérieur à" sont alors généralement interprété comme une entrée ou une sortie pouvant également entrer en conflit. Vous trouverez une liste exhaustive des personnages à éviter ici: http://www.robvanderwoude.com/escapechars.php

0
ner0