web-dev-qa-db-ja.com

Pythonのメモリに数百万のデータのリストを保持することは考えられますか?

私は過去30日間、Pythonアプリケーション(特にノルウェーの住所に関する)のMySQLデータベースを利用して住所の検証と修正を実行するアプリケーションを開発しています。データベースには約210万行(43列)のデータで、640MBのディスク領域を占有します。

私は速度の最適化について考えています。10,000以上のアドレスを検証する場合、各検証でデータベースに対して最大20のクエリが実行され、ネットワーキングが速度のボトルネックであると想定しなければなりません。

まだ測定やタイミングを行っていませんが、現時点でアプリケーションを最適化する速度を上げる簡単な方法があると確信していますが、この量のデータをロードすることがいかに現実的であるかについて専門家の意見を得たいと思いますPythonで行の構造に変換します。また、それはもっと速くなりますか?確かにMySQLは膨大な量のデータの中からレコードを検索するために最適化されているので、ネットワーキングのステップを削除することでさえどれほどの助けになるでしょうか?ネットワーキングのステップを削除する他の実行可能な方法を想像できますか?

MySQLサーバーの場所は、アプリケーションが自宅のラップトップから、またはサーバーがローカルであるオフィスで実行される可能性があるため、異なります。

4
Hubro

210万行すべてをメモリにロードすることは避けます(少なくとも、そうすることは最初の選択ではありません)。これを1つのクエリで実行できたとしても、メモリの問題を回避したとしても、そのすべてのデータをクライアントに取得するにはまだ時間がかかります。そのデータのルックアップは、ネットワークを介した多くのSQLクエリよりもおそらく高速かもしれませんが、それが本当に初期ロードに比べて効果があるかどうかは疑問です(もちろん、確実に測定する必要があります)。

私が正しければ、検証を実行するのにそのすべてのデータは必要ありません-必要なのは、約10.000アドレスのデータと、同等のサイズのデータ​​ベースからのレコード数だけです。おそらく、データを正確に取得するためにクエリの数を減らすことを試みます。おそらく、アドレスごとに20クエリは必要なく、10に減らすことができますか?これが始まりです。ステートメントのIN句でORまたはWHERE演算子を使用して、1つのクエリで複数のアドレスのデータを取得するのではなく、少量のデータの場合、クエリの数のみが重要な要素になることが多いため、これもおそらく役立つでしょう。10、100、または1000バイトの結果セットを取得する場合はそうではありません。

より具体的なアドバイスが必要な場合は、使用しているデータモデルとクエリに関する詳細を提供する必要があります。

編集:アドレスデータベースが数か月間凍結されていると仮定すると、データベース全体のローカルコピーをキャッシュとして使用できます。 SqlLiteのようなものがここでの論理的な選択になるはずです。データ全体を1つのファイルに格納できる、非常に高速でサーバーレスのインプロセス(およびオプションでインメモリ)データベースです。必要なすべてのクエリにSQLを引き続き使用でき、MySQLテーブルからSqlLiteテーブルへの移行は簡単です(これまでのところ、現在のデータベースでMySQL固有のものを使用していない限り)。

データベーステーブルのローカルコピーを完全にPython row-of-rows)に保持しようとしている場合、データモデルの複雑さによっては、おそらく次のようなものを構築することになると考えてください。自分の「貧乏人」インメモリデータベースを自分で作成するのはなぜでしょうか。

SqlLiteに関する情報Pythonインターフェース: http://docs.python.org/2/library/sqlite3.html 。別の利点:住所データが更新された場合サーバーでは、このアプローチにより、サーバー上でデータベースコピーを作成し、ネットワーク経由で1つのファイルのデータをクライアントに送信することができます。

3
Doc Brown

Doc Brownの回答とMason Wheelerのコメントは、おそらくここに行くための最良かつ最も実用的な方法です。とはいえ、これは興味深い概念的な質問なので、コメントする傾向があります。

また、それはもっと速くなりますか?確かにMySQLは膨大な量のデータの中からレコードを検索するために最適化されているので、ネットワーキングのステップを削除することでさえどれほどの助けになるでしょうか?

私たちは本質的に2つのことについて話している:データをクライアント側に持つことと、データセットで検索を行うための「カスタムコード」を持つこと。この配置について私が見る利点:

  • 往復時間の短縮;パフォーマンスについては、何かを確認するためにmeasureにする必要がありますが、シナリオの大部分が200 000クエリがネットワーク経由で渡される(および戻る)のを待つことによって支配されていることが判明した場合、クライアントにデータがあることは間違いなく役立ちます。また、作業をクライアントにオフロードするので、同時に多くのクライアント(たとえば、数千以上)を想定しているシナリオで役立ちます。
  • データに関する深い知識とデータ構造の微調整; MySQLのエンジンは確かに非常に最適化されていますが、保存しているデータが本当にわかりません(アドレスか電話番号かは関係ありません)または患者情報)。この事実を利用して、すばやく検索できるように情報をエンコードする巧妙な方法を考え出すことができます。例えば。ほとんどのノルウェーの通りが番地で始まり、その通りの最後の番号までほとんど連続していることがわかっている場合は、かなり効率的な検索メカニズムを作成できます。番地はその通りの最小値と最大値の間にあり、例外リストにありませんか?それはその通りの有効な住所です。偶然にも、このタイプのことはDBでも行うことができます。主な違いは、データ構造を自分で選択して調整できることです(たとえば、カスタムハッシュアルゴリズムなど)。

2番目のポイントは、おそらくDBのより小さな表現を考え出すために使用できます。現時点でデータがどのように正規化されているかはわかりませんが、通常、アドレスDBはテキストのアドレスの多くを持っている傾向があり、そのほとんどは何度も何度も何度も複製されます。これは、物事を保存する効率的な方法ではありません。これがDBに当てはまる場合は、はるかにコンパクトなファイルで表される可能性があります(DBをZipまたはRARですばやくテストして、重複が多いかどうかを確認しますただし、データの分布は、これらのアルゴリズムができる限り役に立たないことを意味する場合があります)。余談ですが、ストリート番号がテキストとしてストリート名と混在している場合、索引付けのためにDBを最適化するために多くのことができると思います。

TL; DR:はい、理論的には、データをクライアント側に移動することからいくつかの利点を得ることができます。ただし、実際には、クエリをバッチ処理するか、既に投稿されている他の優れたアイデアを使用する方がはるかに良いでしょう。

2
Daniel B

この種のジョブにpythonリストを使用しようとすると、問題が発生します。メモリのオーバーヘッドが大きくなり、データで何か有用なことを行えなくなる可能性があります。

配列をチェックする必要があります( http://docs.python.org/2/library/array.html )、または可能であれば( http://numpy.scipy.org/ )。

それでもすべてのデータをメモリにロードできない場合は、チャンクで処理してクエリの数を制限することができます。

1
Simon Bergot