2

約 170 万行、合計 1 GB のスプレッドシートがあり、さまざまなクエリを実行する必要があります。Python に最も慣れている私の最初のアプローチは、作成しようとしていたクエリを容易にする方法でキーを設定した一連の辞書をハックすることでした。たとえば、特定の市外局番と年齢を持つすべての人にアクセスできるようにする必要がある場合、areacode_age 2 次元辞書を作成します。最終的にかなりの数のこれらが必要になり、メモリ フットプリントが倍増しました (約 10GB のオーダーまで)。これをサポートするのに十分な RAM があったにもかかわらず、プロセスは依然として非常に低速でした。

この時点で、私はカモのゲームをしているように見えました。「まあ、これがリレーショナル データベースの目的ですよね?」と私は思いました。sqlite3 をインポートし、データをインメモリ データベースにインポートしました。データベースは速度を重視して構築されており、これで問題が解決すると思います。

ただし、「SELECT (a, b, c) FROM foo WHERE date1<=d AND date2>e AND name=f」のようなクエリを実行すると、0.05 秒かかることがわかります。170 万行でこれを行うと、24 時間の計算時間がかかります。辞書を使った私のハッキーなアプローチは、この特定のタスクで約 3 桁高速でした (そして、この例では明らかに date1 と date2 をキーにすることができなかったため、名前に一致するすべての行を取得し、日付でフィルタリングしていました)。

それで、私の質問は、なぜこれがそんなに遅いのか、どうすれば速くできるのかということです. Pythonic アプローチとは何ですか? 私が検討してきた可能性:

  • sqlite3 は遅すぎるので、もっと重いものが必要です
  • 何らかの方法でスキーマまたはクエリを変更して、より最適化する必要がありますか?
  • これまでに試したアプローチは完全に間違っており、まったく新しいツールが必要です
  • sqlite 3 で、cursor.execute を繰り返し呼び出すと、cursor.executemany を使用するよりもはるかに遅いことをどこかで読みました。ただし、executemany は select ステートメントとさえ互換性がないことが判明したため、これはニシンだったと思います。

ありがとう。

4

3 に答える 3

4

sqlite3 は遅すぎるので、もっと重いものが必要です

まず、sqlite3 は高速で、MySQL よりも高速な場合もあります

次に、インデックスを使用する必要があります。複合インデックスを (date1, date2, name) に配置すると、処理が大幅に高速化されます

于 2012-03-14T02:23:56.150 に答える
2

ただし、「SELECT(a、b、c)FROM foo WHERE date1 <= d AND date2> e AND name=f」のようなクエリを実行するには0.05秒かかります。170万行に対してこれを行うと、24時間の計算時間がかかります。辞書を使った私のハッキーなアプローチは、この特定のタスクで約3桁高速でした(この例では、date1とdate2を明らかにキー入力できなかったため、名前に一致するすべての行を取得してから、日付でフィルタリングしていました)。

実際にこれを試して、24時間かかっていることを確認しましたか?処理時間は、必ずしもデータサイズに直接比例するわけではありません。

SELECT (a, b, c) FROM foo WHERE date1<=d AND date2>e AND name=fそして、 170万回実行する必要があるかもしれないと示唆していますか?一度実行するだけで、クエリに一致する行のサブセット全体が返されます。

170万行は小さくはありませんが、ローカルコンピュータの完全にメモリ内にあるデータベースにとっては確かに問題ではありません。(低速のディスクアクセス、低速のネットワークアクセスはありません。)


証拠はプリンにあります。これは私にとってはかなり高速です(ほとんどの時間は約1,000万のランダムフロートの生成に費やされます)。

import sqlite3, random

conn = sqlite3.connect(":memory:")
conn.execute("CREATE TABLE numbers (a FLOAT, b FLOAT, c FLOAT, d FLOAT, e FLOAT, f FLOAT)");
for _ in xrange(1700000):
    data = [ random.random() for _ in xrange(6) ];
    conn.execute("INSERT INTO numbers VALUES (?,?,?,?,?,?)", data)

conn.commit()

print "done generating random numbers"

results = conn.execute("SELECT * FROM numbers WHERE a > 0.5 AND b < 0.5")
accumulator = 0
for row in results:
    accumulator += row[0]

print ("Sum of column `a` where a > 0.5 and b < 0.5 is %f" % accumulator)

編集:さて、あなたは本当にこれを170万回実行する必要があります。

その場合、おそらく必要なのはインデックスです。ウィキペディアを引用するには:データベースインデックス:

データベースインデックスは、データベーステーブルでのデータ取得操作の速度を向上させるデータ構造ですが、書き込みが遅くなり、ストレージスペースが増加します。インデックスは、データベーステーブルの1つ以上の列を使用して作成でき、高速ランダムルックアップと順序付けされたレコードへの効率的なアクセスの両方の基盤を提供します。

あなたは次のようなことをしてCREATE INDEX dates_and_name ON foo(date1,date2,name)から(私は信じています)残りのSELECTステートメントをいつものように実行します。これを試して、速度が上がるかどうかを確認してください。

于 2012-03-14T02:15:43.183 に答える
0

すでにSQLについて話しているので、最も簡単なアプローチは次のとおりです。

  1. すべてのデータをMySQLテーブルに配置します。170万行でうまく機能するはずです。
  2. 必要なインデックスを追加し、設定を確認し、大きなテーブルで高速に実行されることを確認します。
  3. Pythonからアクセスする
  4. ..。
  5. 利益!
于 2012-03-14T02:20:53.383 に答える