2009-03-18 13 views
50

Próbuję załadować dużą ilość danych (5,5 miliona wierszy) do pliku bazy danych SQLite. Ładowanie przez INSERTs wydaje się być zbyt wolne, dlatego próbuję użyć narzędzia wiersza poleceń sqlite3 i polecenia .import.Jak zautomatyzować proces za pomocą narzędzia wiersza polecenia sqlite3.exe?

Działa to doskonale, jeśli ręcznie wpisuję komendy, ale nie mogę do końca pracować nad tym, jak zautomatyzować skrypt (plik .bat lub python, pracuję na komputerze z systemem Windows).

Polecenia I wydać w wierszu polecenia są takie:

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

Ale nic staram się uzyskać to do pracy z pliku bat lub skrypt Pythona.

Próbowałem rzeczy jak:

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

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

pewnością mogę to zrobić w jakiś sposób?

+0

Jak powolne jest ładowanie za pomocą INSERT? Wstawiam 15 milionów dużych wierszy w Sqlite w 12 minut za pomocą instrukcji insert. Musisz korzystać z transakcji i przygotowanych wyciągów. – tuinstoel

+0

Bardzo wolno. Używam Pythona do parsowania pliku dziennika i wstawiania każdego wiersza jako wiersz. Nie używam przygotowanych wyciągów, ale korzystam z transakcji. Mimo to jest to o wiele szybsze, dzięki programowi sqlite3. – dave

+0

Używanie przygotowanych oświadczeń ma ogromne znaczenie. Mogę utworzyć bazę danych o pojemności dwóch gigabajtów sqlite (1 duży stół z 1 indeksem) w ciągu 12 minut za pomocą INSERT na standardowym komputerze. – tuinstoel

Odpowiedz

47

Utwórz plik tekstowy z linii, które mają wejść do sqlite programem wiersza poleceń, tak:

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

a potem po prostu zadzwonić sqlite3 database.db < commands.txt

+0

Twoje rozwiązanie jest poprawne, ponieważ utknąłem, ponieważ nie możesz mieć spacji przed kropką. polecenie w swoim skrypcie. FYI – ozmike

15

Utwórz osobny plik tekstowy zawierający wszystkie polecenia zwykle wpisujesz w aplikacji powłoki sqlite3:

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

Zapisz to jako, powiedzmy, impscript.sql.

Utwórz plik wsadowy, który wywołuje skorupę sqlite3 z tego skryptu:

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

Połącz plik wsadowy.

Na marginesie - podczas importowania, , zapisz INSERTs w transakcji! To da ci natychmiastowe przyspieszenie o 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 

ale jest niemożliwe, aby napisać jak jak napisałeś

+1

Wywołanie ".separator", "" nie działa, gdy uruchamiasz wiele procesów sqlite, jak wskazałeś powyżej. –

+0

Dziękuję bardzo za przekazanie tej informacji. – Bhargava

23

Alternatywnie można umieścić wszystko w jednym pliku skryptu powłoki (konserwacyjnych co upraszcza) używając heredocimport.sh:

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

... i uruchom:

import.sh database.db 

Ułatwia utrzymanie tylko jednego pliku skryptu. Nawiasem mówiąc, jeśli chcesz uruchomić go pod Windows, Power Shell also features heredoc

Ponadto to podejście pomaga radzić sobie z brakiem obsługi parametrów skryptu.Można używać zmiennych bash:

#!/bin/bash -- 

table_name=log_entry 

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

Albo nawet zrobić trick tak:

#!/bin/bash -- 

table_name=$2 

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

... i uruchom go: import.sh database.db log_entry

+0

Autor - wzmianki o pracy nad oknem -FYI – ozmike

5

Właśnie niedawno miał podobny problem podczas konwersji Firefoksa "cookies.sqlite do pliku tekstowego (dla niektórych narzędzi do pobierania) i natknąłem się na to pytanie.

chciałem zrobić z jednej linii i powłoki, która byłaby stosowana do mojego rozwiązania powyższego problemu:

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

Ale nie testowane jeszcze tę linię. Ale to działało dobrze z problemem Firefox wspomniałem powyżej (btw poprzez Bash na 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

Mogę potwierdzić, że ta metoda działa; po prostu wypróbowałem to na OSX bez problemu. –

+1

Autor - wspomina, że ​​pracuje nad oknem -FYI – ozmike

+0

Nie ma takiego polecenia, jak'echo -e' pod oknami. Jak już powiedział ozmike autor mówi "Pracuję na komputerze z systemem Windows". – PeterCo

1

W tym momencie, nie jestem pewien, co jeszcze mogę dodać inny niż miałem pewne problemy dodanie Zmienna środowiskowa unix do skryptu bash sugerowana przez nad2000.

działa następująco:

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

potrzebowałem importować z stdin jako obejście i znalazłem to rozwiązanie:

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

Dodając drugą linię sqlite3, udało mi się przekazać $ 2 od Unix do parametru pliku dla .import, pełnej ścieżki i wszystkiego.

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

Witamy w Stack Overflow! Ten fragment kodu może rozwiązać pytanie, w tym wyjaśnienie [naprawdę pomaga] (// meta.stackexchange.com/q/114762) w celu poprawy jakości Twojego posta. Pamiętaj, że odpowiadasz na pytanie dla czytelników w przyszłości, a nie tylko pytasz teraz! Proszę [edytuj] swoją odpowiedź, aby dodać wyjaśnienie i podać, jakie ograniczenia i założenia mają zastosowanie. –

0

W systemie Windows, to powinno działać:

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

Nie testowałem tego konkretnego polecenia, ale z moim dążeniu do rozwiązania tego problemu rurowych wielu poleceń Uważam, że kluczem było ująć echo poleceń w nawiasach. Biorąc to pod uwagę, możliwe, że będziesz musiał poprawić powyższe polecenie, aby uciec z niektórych z tych znaków. Na przykład:

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

Nie jestem pewien, czy wyciek jest potrzebne w tym przypadku, ale jest wysoce prawdopodobne, ponieważ nawiasy mogą być sprzeczne z tych zamykających, a następnie „mniej niż” i "większa niż "symbole są zwykle interpretowane jako dane wejściowe lub wyjściowe, które również mogą być w konflikcie. Obszerną listę znaków ucieczki można znaleźć tutaj: http://www.robvanderwoude.com/escapechars.php

Powiązane problemy