2017-02-07 3 views
1

Ich habe ein Skript, das ein in einer Datenbank gespeichertes Datum von Unix Time (Epoche) in ein für Menschen lesbares Format konvertiert. Es gibt 30.000 Datensätze.
Um die Daten aus der Datenbank zu ziehen, konvertieren Sie es und drucken Sie es auf dem Bildschirm ist sehr schnell. Um jedoch die Daten aus der Datenbank zu holen, sie zu konvertieren und eine "update" -Anweisung auszuführen, um den Datensatz zu aktualisieren, ist extrem langsam.
Gibt es trotzdem den folgenden Code zu optimieren, um diesen Prozess für die 30.000 Datensätze, die ich habe, zu beschleunigen?Python SQLite - Langsame UPDATE-Datensätze

cur.execute('select Atime from Hash where Atime like (?) ', (test,)) 
    results = cur.fetchall() 
    for row in results: 
     convertedtime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime((float(row[0])))) 
     print convertedtime 
     cur.execute('Update Hash set Atime = (?) where Atime = (?)', (convertedtime, row[0])) 
    con.commit() 

Die con.commit() ist außerhalb der for-Schleife, so dass es mit zu begehen Aufzeichnungen nach jeder Iteration kein Problem ist.

+0

Enthält diese Änderungen vornehmen: https://sqlite.org/pragma.html#pragma_synchronous –

+0

Wie groß ist der db-Datei? Sie könnten versuchen, alles in Pandas zu importieren, zu manipulieren und dann nach sqlite zu exportieren. – rshield

+0

möglicherweise, weil das Feld nicht indiziert ist? – asiviero

Antwort

3

Das größte Performance-Problem ist, dass Sie die Daten aus SQLite sind ziehen, es in Python Laden, es in Python konvertieren, dann ist es wieder in die Datenbank ein Datum zu einem Zeitpunkt setzen. Dies wird niemals effizient sein.

Stattdessen use SQLite's own built in date and time functions. Es sieht aus wie atime ist Unix Epoche Zeit.

update hash set atime = datetime(atime, 'unixepoch', 'localtime'); 

Aber Sie wahrscheinlich nicht wollen, Termine in der lokalen Zeitzone speichern. Zeitzonen werden kompliziert, und es gibt Sommerzeit, die fehlende und überlappende Zeiten hat ... es führt nur zu Tränen. Sie möchten definitiv keine Datetime in der lokalen Zeitzone speichern, ohne anzugeben, um welche Zeitzone es sich handelt!

Sofern Sie keinen wirklich guten Grund haben, speichern Sie es als UTC.

update hash set atime = datetime(atime, 'unixepoch'); 

Im Allgemeinen, wenn Sie das tun wollen, um die Dinge SQLite nicht unterstützt, erstellen eine benutzerdefinierte Funktion und in einer Abfrage verwenden. Dies ist weniger effizient als die Verwendung integrierter SQLite-Funktionen, jedoch effizienter als das Auswählen, Konvertieren und Aktualisieren.

Es würde ungefähr so ​​aussehen.

def epoch_to_iso8601(epoch): 
    return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime((float(epoch)))) 

con.create_function("epoch_to_iso8601", 1, epoch_to_iso8601) 

Dann können Sie epoch_to_iso8601 in einer Abfrage verwenden.

update hash set atime = epoch_to_iso8601(atime); 

Beachten Sie, dass dies nicht mit einer gespeicherten Prozedur identisch ist. Da kein SQLite-Server vorhanden ist, wird der gesamte Code in Ihrem Prozess ausgeführt. Diese Funktion wird pro Prozess ausgeführt.

Siehe sqlite3.create_function.


Das eigentliche Problem hier ist, dass Sie als Datetimes Strings sind zu speichern. Dies macht sie langsam und schwierig zu arbeiten. Es bedeutet, dass Sie eine einzelne Formatierung auswählen müssen. Es bedeutet, dass Sie dieses Format analysieren müssen, um irgendetwas damit zu tun. Das bedeutet, dass Sie die integrierten SQLite-Datums- und Zeitfunktionen (so dünn wie sie sind) nicht verwenden können.

Was Sie eigentlich tun möchten, ist atime als Unix-Epoche Zeit und formatieren Sie es, wie Sie pro Abfrage benötigen.

select datetime(atime, 'unixepoch') from hash; 

Glücklicher SQLite ist sehr loosey-goosey mit seiner Art und wird den Text atime Feld auf eine Nummer für Sie konvertieren, obwohl es eine Performance und Speicher Strafe verbunden sein wird.


Im Idealfall würde Sie atime zu ändern, um die datetime Typ zu verwenden, aber das ist in SQLite schwierig. Es unterstützt nicht das Entfernen oder Ändern vorhandener Spalten. Stattdessen müssten Sie die Daten in der Tabelle ausgeben, die Tabelle neu erstellen und die Daten importieren. Dies sollte mit nur 30.000 Datensätzen sehr schnell sein.

Wechseln Sie in den CSV-Modus, senden Sie die Ausgabe an eine Datei und wählen Sie alles aus.

sqlite> .mode csv hash 
sqlite> .output hash.out 
sqlite> select * from hash; 

Löschen Sie die vorhandene Tabelle und erstellen Sie es das gleiche, aber mit atime als datetime.

sqlite> drop table hash; 
sqlite> create table hash (atime datetime, and the other columns); 

Importieren Sie den Speicherauszug.

sqlite> .import hash.out hash 
+1

Danke für den Info-Partner - ich werde einen Blick darauf werfen und ein paar Tests durchführen und Bericht erstatten! –

+0

Vielen Dank für Ihre Hilfe - ich endete mit dem folgenden Befehl: cur.execute ("UPDATE Hash SET Atime = DatumZeit (Atime, (?))", ('Unixepoch')) ----- Arbeitete wie ein Charme ! –