2017-02-07 5 views
1

データベースに保存されている日付をUnix Time(epoch)から人間が読める形式に変換するスクリプトがあります。 30,000のレコードがあります。
データベースからデータを取り出し、変換して画面に印刷するのは非常に高速です。しかし、データベースからデータを取り出し、変換してレコードを更新するための「更新」ステートメントを実行すると、非常に遅いです。
私は30,000レコードのためにこのプロセスを高速化するために、次のコードを最適化する方法はありますか?それはすべての反復後、レコードをコミットすると問題ではありませんのでPython SQLite - 遅い更新レコード

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() 

con.commit()は、forループの外にあります。

+0

これは、任意の変更を行うん:https://sqlite.org/pragma.html#pragma_synchronous –

+0

デシベルファイルがどのくらいありますか?あなたはそれをすべてpandasにインポートし、操作してsqliteにエクスポートしようとするかもしれません。 – rshield

+0

フィールドがインデックスに登録されていない可能性がありますか? – asiviero

答えて

3

の主要なパフォーマンスの問題は、SQLiteのからデータを引っ張ってのPythonにそれをロードし、Pythonでそれを変換し、その後、時間でデータベース1日に戻ってそれを入れているです。これは決して効率的ではありません。

代わりに、use SQLite's own built in date and time functions。 Unixのエポックタイムはatimeのようです。

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

しかし、あなたはおそらくローカルタイムゾーンで日付を格納する必要はありません。タイムゾーンが複雑になり、夏時間が失われて重複している...涙が出るだけです。間違いなく、そのタイムゾーンが何であるかを明示せずに、ローカルタイムゾーンにdatetimeを格納することは望ましくありません。

本当に良い理由がない限り、UTCとして保存してください。一般的に

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

、あなたはSQLiteのは、サポートされていないもの、は、ユーザー定義関数を作成し、クエリで使用をしたい場合。これは、組み込みSQLite関数を使用するより効率的ではありませんが、選択、変換、および更新よりも効率的です。

このようになります。

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) 

次に、epoch_to_iso8601をクエリに使用できます。

update hash set atime = epoch_to_iso8601(atime); 

これはストアドプロシージャと同じではありません。 SQLiteサーバーがないので、すべてのコードがプロセス内で実行されています。この関数はプロセスごとです。

sqlite3.create_functionを参照してください。


ここでの本当の問題は、あなたが、文字列として日付時刻を保存しているです。これにより、彼らは遅くて扱いにくいものになります。つまり、1つの書式を選択する必要があります。つまり、そのフォーマットを解析して何かを行う必要があるということです。つまり、組み込みのSQLiteの日付と時刻関数(疎である)を使用することはできません。

あなたが実際にやりたいことは、atimeをUnixのエポックタイムとして残し、必要に応じてそれをフォーマットします。

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

幸いSQLiteはそのタイプで非常にloosey-gooseyであり、それは、パフォーマンスとストレージのペナルティが発生しますが、あなたのための番号にテキストatimeフィールドを変換します。


理想的には、datetimeタイプを使用するようにatimeを変更したいと思いますが、これはSQLiteのでは困難です。既存の列の削除または変更はサポートされていません。代わりに、テーブルにデータをダンプし、テーブルを再作成し、データをインポートする必要があります。これはわずか30,000レコードで非常に高速になるはずです。

CSVモードに切り替え、出力をファイルに送信し、すべてを選択します。

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

既存のテーブルを削除し、同じですが、datetimeとしてatimeでそれを再作成します。

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

ダンプをインポートします。

sqlite> .import hash.out hash 
+1

情報メイトに感謝しています。 –

+0

あなたの助けてくれてありがとう - 私は次のコマンドを使用して終了しました:cur.execute( "UPDATEハッシュSET Atime = datetime(Atime、(?))"、( 'unixepoch'))----- チャームのように働いた! –