2013-08-20 5 views
6

私はSELECTクエリのデータベースにスクリプトを書いていて、〜33,000個のレコードを解析しています。残念ながら、cursor.fetchone()/cursor.fetchall()段階の問題が発生しています。fetchoneでPythonが遅く、fetchallでハングアップ

私が最初にそうような時に、カーソルを使用してレコードを反復処理しようとした:

# Run through every record, extract the kanji, then query for FK and weight 
printStatus("Starting weight calculations") 
while True: 
    # Get the next row in the cursor 
    row = cursor.fetchone() 
    if row == None: 
     break 

    # TODO: Determine if there's any kanji in row[2] 

    weight = float((row[3] + row[4]))/2 
    printStatus("Weight: " + str(weight)) 

printStatusの出力に基づいて、(それがタイムスタンプを出力プラスに渡されるどんな文字列)、スクリプトがかかりました各行を処理するのに約1秒かかる。これは、SQLiteStudio [i]や[/]などで同じクエリを1回実行するのに約1秒かかったので、ループが繰り返されるたびに(LIMIT 1などで)クエリが再実行されていると考えられます私は33,000行すべてを返します。私は、その率では、33,000レコードすべてを取得するのに約7時間かかると計算しました。

はその代わりを通じて座って、私が代わりに)(cursor.fetchallを使用しようとしました:それはcursor.fetchall()に着いたとき

results = cursor.fetchall() 

# Run through every record, extract the kanji, then query for FK and weight 
printStatus("Starting weight calculations") 
for row in results: 
    # TODO: Determine if there's any kanji in row[2] 

    weight = float((row[3] + row[4]))/2 
    printStatus("Weight: " + str(weight)) 

を残念ながら、実行可能なPythonは、25%のCPUとRAMの〜6メガバイトでロックアップライン。私はスクリプトを約10分間走らせておきましたが、何も起こりませんでした。

Pythonが一度に取得するには〜33,000行(約5MBのデータ)が返されますか?私は一度に1つずつ繰り返されますか?それとも、スピードアップのためにできることはありますか?

EDITには:Here some consoleのoutput

12:56:26.019: Adding new column 'weight' and related index to r_ele 
12:56:26.019: Querying database 
12:56:28.079: Starting weight calculations 
12:56:28.079: Weight: 1.0 
12:56:28.079: Weight: 0.5 
12:56:28.080: Weight: 0.5 
12:56:28.338: Weight: 1.0 
12:56:28.339: Weight: 3.0 
12:56:28.843: Weight: 1.5 
12:56:28.844: Weight: 1.0 
12:56:28.844: Weight: 0.5 
12:56:28.844: Weight: 0.5 
12:56:28.845: Weight: 0.5 
12:56:29.351: Weight: 0.5 
12:56:29.855: Weight: 0.5 
12:56:29.856: Weight: 1.0 
12:56:30.371: Weight: 0.5 
12:56:30.885: Weight: 0.5 
12:56:31.146: Weight: 0.5 
12:56:31.650: Weight: 1.0 
12:56:32.432: Weight: 0.5 
12:56:32.951: Weight: 0.5 
12:56:32.951: Weight: 0.5 
12:56:32.952: Weight: 1.0 
12:56:33.454: Weight: 0.5 
12:56:33.455: Weight: 0.5 
12:56:33.455: Weight: 1.0 
12:56:33.716: Weight: 0.5 
12:56:33.716: Weight: 1.0 

'sそしてhere SQLのquery's:

0 0 0 SCAN TABLE r_ele AS re USING COVERING INDEX r_ele_fk (~500000 rows) 
0 0 0 EXECUTE CORRELATED SCALAR SUBQUERY 1 
1 0 0 SEARCH TABLE re_pri USING INDEX re_pri_fk (fk=?) (~10 rows) 
0 0 0 EXECUTE CORRELATED SCALAR SUBQUERY 2 
2 0 0 SEARCH TABLE ke_pri USING INDEX ke_pri_fk (fk=?) (~10 rows) 
2 0 0 EXECUTE CORRELATED SCALAR SUBQUERY 3 
3 0 0 SEARCH TABLE k_ele USING AUTOMATIC COVERING INDEX (value=?) (~7 rows) 
3 0 0 EXECUTE CORRELATED SCALAR SUBQUERY 4 
4 0 0 SEARCH TABLE k_ele USING COVERING INDEX idx_k_ele (fk=?) (~10 rows) 
0 0 0 EXECUTE CORRELATED SCALAR SUBQUERY 5 
5 0 0 SEARCH TABLE k_ele USING COVERING INDEX idx_k_ele (fk=?) (~10 rows) 
0 0 0 EXECUTE CORRELATED SCALAR SUBQUERY 6 
6 0 0 SEARCH TABLE re_pri USING INDEX re_pri_fk (fk=?) (~10 rows) 
0 0 0 EXECUTE CORRELATED SCALAR SUBQUERY 7 
7 0 0 SEARCH TABLE ke_pri USING INDEX ke_pri_fk (fk=?) (~10 rows) 
7 0 0 EXECUTE CORRELATED SCALAR SUBQUERY 8 
8 0 0 SEARCH TABLE k_ele USING AUTOMATIC COVERING INDEX (value=?) (~7 rows) 
8 0 0 EXECUTE CORRELATED SCALAR SUBQUERY 9 
9 0 0 SEARCH TABLE k_ele USING COVERING INDEX idx_k_ele (fk=?) (~10 rows) 
+7

カーソルの反復処理を試みましたか? 'for row in cursor:...'? –

+0

'fetchone'(またはiterating)が毎回クエリを再実行する方法はありません。 'cursor'オブジェクトは一般に、それが実行されたクエリを知りません。だから、あなたの問題が何であれ、それはそうではありません。 – abarnert

+0

また、サイドノートとして 'if row is None:'ではなく 'if row == None:'を使用しないでください。ほとんどの場合、それは実際には何の違いもありませんが、もっと慣れています(少し速くなり、まれに、あなたが望むものに違いが生じます)。 – abarnert

答えて

3

SQLite computesに:

//...snip (it wasn't the culprit)... 

SQLiteStudioでのクエリ・プランをEXPLAINのoutput結果の記録はオンザフライで表示されます。 fetchoneは、各レコードのすべてのサブクエリをr_eleに実行する必要があるため、処理速度が遅くなります。 fetchallは、すべてのレコードに対してfetchoneを実行したのと同じくらい時間がかかるため、さらに遅くなります。

SQLite 3.7.13は、value列のすべてのルックアップがひどく遅くなるため、このクエリの一時インデックスを作成すると推定しています。それでも解決しない場合は

CREATE INDEX idx_k_ele_value ON k_ele(value); 

新しいSQLiteのバージョンではPythonに、更新、またはそれ以降で、別のデータベースライブラリを使用します。 あなたはそれがSQLiteの3.6.21で使用することができるように永続索引を作成する必要がありますAPSWなどのSQLiteバージョンが組み込まれています。

+0

これはPythonの問題ではありませんでしたが、適切なインデックスが不足していました。上記のインデックスを作成した後、Pythonは33,000レコードすべてを約2.5秒で噛み、SQlite Studioの実行時間は約1.75秒から0.0006秒になりました。 – IAmKale

関連する問題