2011-05-09 11 views
18

"Konwertuję" duży (~ 1.6GB) plik CSV i wstawiam określone pola CSV do bazy danych SQLite. Zasadniczo mój kod wygląda następująco:Python CSV do SQLite

import csv, sqlite3 

conn = sqlite3.connect("path/to/file.db") 
conn.text_factory = str #bugger 8-bit bytestrings 
cur = conn.cur() 
cur.execute('CREATE TABLE IF NOT EXISTS mytable (field2 VARCHAR, field4 VARCHAR)') 

reader = csv.reader(open(filecsv.txt, "rb")) 
for field1, field2, field3, field4, field5 in reader: 
    cur.execute('INSERT OR IGNORE INTO mytable (field2, field4) VALUES (?,?)', (field2, field4)) 

Wszystko działa jak oczekuję go z wyjątkiem ... Trwa niesamowita ilość czasu na przetworzenie. Czy koduję go niepoprawnie? Czy istnieje lepszy sposób na osiągnięcie wyższej wydajności i osiągnięcie tego, czego potrzebuję (wystarczy przekonwertować kilka pól pliku CSV na tabelę SQLite)?

** EDYCJA - próbowałem bezpośrednio importować csv do sqlite zgodnie z sugestiami, ale okazało się, że mój plik ma przecinki w polach (np. "My title, comma"). To powoduje błędy przy imporcie. Wydaje się, że jest zbyt wiele z tych zdarzeń ręcznie edytować plik ...

wszelkie inne myśli ?? **

+1

To duży plik. Jak dużo czasu to zajmuje? – Blender

+0

Ile jest zduplikowanych rekordów? Jeśli jest ich dużo, prawdopodobnie będzie to szybsze przechowywanie lokalnego 'zestawu' rekordów, które już zostały wstawione, i pominięcie wywołania do SQL w całości dla duplikatów. – kindall

+0

[tutaj] (http://dev.mysql.com/doc/refman/5.5/en/insert-speed.html) to niektóre wskazówki dotyczące prędkości ładowania zbiorczego MySQL. – kindall

Odpowiedz

24

Jest to możliwe, aby zaimportować plik CSV bezpośrednio:

sqlite> .separator "," 
sqlite> .import filecsv.txt mytable 

http://www.sqlite.org/cvstrac/wiki?p=ImportingFiles

+1

"bla, bla, bla", "123" powoduje problemy ... myśli wokół tego? – user735304

+0

Wygląda na to, że domyślnie nie ma wbudowanego sposobu unikania. Ponadto, cytaty będą literałami w ciągu znaków. Zmiana tekstu za pomocą analizy pliku CSV może być sensowna i wysyłanie go z innym separatorem, ale może to w ogóle uniemożliwić korzystanie z narzędzia do importowania. – fengb

+0

Spróbuj: .mode csv zamiast .separatora, zobacz: http://stackoverflow.com/questions/14947916/import-csv-to-sqlite/24582022#24582022 – NumesSanguis

3

Spróbuj użyć transakcji.

begin  
insert 50,000 rows  
commit 

To spowoduje, że dane będą przesyłane okresowo, a nie raz w rzędzie.

20

Chris ma rację - wykorzystuj transakcje; podziel dane na porcje, a następnie przechowuj je.

"... O ile nie jest już w transakcji, każda instrukcja SQL ma dla niej nową transakcję, jest to bardzo kosztowne, ponieważ wymaga ponownego otwarcia, zapisania i zamknięcia pliku kroniki dla każdego wyciągu. należy unikać owijając sekwencje instrukcji SQL z rozpocząć transakcji, a końca transakcji; sprawozdanie to przyspieszenie uzyskuje się również do wypowiedzi, które nie zmieniają bazę „- Źródło: http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html

... nie ma.. kolejna sztuczka, której możesz użyć, aby przyspieszyć SQLite: transakcje, kiedy musisz wykonać wiele zapisów do bazy danych, umieść je w transakcji, zamiast zapisywać (i blokować) plik za każdym razem zapytanie pisane zostanie wydane, zapis nastąpi tylko raz, gdy transakcja zostanie zakończona. "- Źródło: How Scalable is SQLite?

import csv, sqlite3, time 

def chunks(data, rows=10000): 
    """ Divides the data into 10000 rows each """ 

    for i in xrange(0, len(data), rows): 
     yield data[i:i+rows] 


if __name__ == "__main__": 

    t = time.time() 

    conn = sqlite3.connect("path/to/file.db") 
    conn.text_factory = str #bugger 8-bit bytestrings 
    cur = conn.cur() 
    cur.execute('CREATE TABLE IF NOT EXISTS mytable (field2 VARCHAR, field4 VARCHAR)') 

    csvData = csv.reader(open(filecsv.txt, "rb")) 

    divData = chunks(csvData) # divide into 10000 rows each 

    for chunk in divData: 
     cur.execute('BEGIN TRANSACTION') 

     for field1, field2, field3, field4, field5 in chunk: 
      cur.execute('INSERT OR IGNORE INTO mytable (field2, field4) VALUES (?,?)', (field2, field4)) 

     cur.execute('COMMIT') 

    print "\n Time Taken: %.3f sec" % (time.time()-t) 
+0

Inny użytkownik po tym kodzie wpadł na problem próbujący użyć 'len()' z ich czytnikiem CSV: http://stackoverflow.com/questions/18062694/sqlite-transaction- for-csv-importing/18063276#18063276 – rutter

14

jak to zostało powiedziane (Chris i Sam), transakcje zrobić poprawić wydajność insert dużo

Proszę, pozwól mi polecić inną opcję, aby użyć zestawu narzędzi Pythona. do pracy z CSV, csvkit

aby zainstalować.

pip install csvkit 

aby rozwiązać problem

csvsql --db sqlite:///path/to/file.db --insert --table mytable filecsv.txt