2016-07-05 20 views
2

pyodbcを使用してMicrosoft Accessデータベースとやり取りするpythonプログラムを作成しました。データベースには、井戸(約630万)の測定値を含むテーブルが含まれています。"システムリソースを超過しました" pyodbcでSELECTクエリを実行するとODBC MS Accessドライバからのエラー

プログラムの基本的な作業の流れは、化学物質のリストを取得することです。次に、すべての化学物質について、その化学物質のデータを持つテーブル内のすべてのウェルを見つけるために選択クエリを使用します。各ウェルについて、化学物質のウェルのすべての測定値を含むデータセットをフェッチするために別の選択クエリを使用する。

このデータセットを取得すると、そのデータセットの化学物質とウェルペアの新しい行を作成するために使用される統計が計算されます。これらの新しい行は、それぞれ新しいデータベース表に出力されます。

私はpythonのマルチプロセッシングパッケージを使用して、プログラムがより多くのCPU容量を使用できるようにしています。プログラムには常に、キューからデータを取り出し、入力データベースから新しい別のデータベースに挿入する1つのコンシューマ・プロセスがあります。次に、プログラムには、化学物質をキューから取り出し、処理し、そこにデータを出力キューに追加する様々な量のプロデューサプロセスがあります。

私はおよその長さである化学リスト上のプログラムを実行すると、それは時々エラーになります。

Starting: 01027 
Failed on 01027 when selecting wells for chemical. 
Failed. Wells processed: 371693 
Traceback (most recent call last): 
    File "C:\Users\jrutledge\Desktop\well_trend_processor_python_2016\python_processor\well_trends.py", line 230, in read_data_sets_into_queue 
    raise e 

これは96の化学物質のリストのためではなく、10以下のために少なくとも一回(時にはそれ以上)が起こります、どこが切れているか分からない。このエラーメッセージの意図された原因は、あまりにも多くのメモリを消費するクエリを実行しているようですが、これはここでの結果ではないようです。 1つの理由は、それが間違っている化学物質が、試み間で一貫していないということです。さらに、化学物質の不足している化学物質を含む小さなリストを実行すると、エラーなしで処理されます。

問題は、私は化学のために井戸を選択していたときに起こっているようだ:

# Find each well that has samples of this chemical 
wells_cursor = measurement_db_chemical.cursor() 
sql_string = """SELECT DISTINCT {0}.Well_ID, PSCODE, STAID, Status 
       FROM {0} 
       LEFT JOIN {1} 
       ON {0}.Well_ID = {1}.Well_ID 
       WHERE STORE_NUM = ?""".format(
        well_records_table_name, well_sites_table_name) 
try: 
    wells_cursor.execute(sql_string, chemical.STORE_NUM) 
# Close db connection if error, outer try will close connection 
except Exception, e: 
    print ('Process {}: Failed on {} when selecting wells for chemical.'.format(process_number, chemical.STORE_NUM)) 
      raise e 

このSQLクエリは道より頻繁に、それはエラーが発生するよりも、問題なく実行されるので、それはないの前に言ったように、が、 SQLにエラーがあるようです。しかし、これはプログラムが作成する最も集中的なクエリであり、リソースを超えるものであることが理にかなっています。

この問題は、プログラムの挿入部分を削除すると解決しません。このようにして、通常どんなこともしますが、統計を計算した後に新しいテーブルに挿入することはありません。

DBへの接続をあまりに長く開いたままにしておけば、何とかガーベッジメモリなどが蓄積されている可能性があると思っていました。これにより、pythonプログラムを各化学物質のデータベースへの新しい接続を開き、その化学物質の処理が完了したら閉じます。しかし、問題は解決しません。

特に、私がそれをどのように実行しても、総メモリ使用量は60%を超えることはありませんので、それは問題ではないと思います。

また、データベースのサイズは800 MB未満です。これは、MS Accessデータベースの2 GBのサイズ制限付近ではありません。

私は1つのプロセスでプログラムを実行していました。これは、誰かが照会を選択しても、ODBCドライバーが処理するにはリソースがあまりにも高価ではないかもしれませんが、同時に複数の実際に高価な照会が実行され、ドライバーがそのリソース制限に達する可能性があると考えています。私は今、プログラムを修正し、python RLocksを追加しました。データベース内でSQLクエリが実行されているので、一度に1つのプログラムしかデータベースから読み取れないため、この問題は解決されません。昨日、4つのプロセスが正常に完了して実行されましたが、この問題は修正されましたが、今日では選択されたウェルのクエリで同じエラーが発生しています。

は(私はそれが解決策だと思ったとき、私は答えとしてこれを掲示し、今それを削除してしまった)。また

ないこの方法のCPU使用率を使用した場合のプロセスが1を待つ必要があるため決して80%の上に行かないこともう1つはクエリに使用され、それでもエラーが発生します。つまり、dbとのODBCドライバのインタフェースには、使用上のコード化された制限が必要です。

このエラーの原因は何だと思いますか、それを修正する方法を教えてください。

もっと多くのコードをご覧になりたい場合は、その部分がたくさんあることを教えてください。

+0

* System Resource Exceeded *が投稿に表示されないため、完全なトレースバックを投稿できますか?また、これはPythonエラーではなく、MS Accessエラーです。通常、このメッセージには、複雑なクエリ、NULL値の処理、予約語、および構文項目が含まれます。 – Parfait

+0

また、テストとして、MSAccess.exe内で同じ操作を実行できますか(Officeプログラムがある場合)? LEFT JOINのDISTINCTはあまり最適化されていません。 – Parfait

+0

@Parfait私はAccessでよく選択されたクエリを実行し、正常に動作します。私は全体の操作を実行する方法がわかりません:100個のクエリを連続して実行しています。それを手動で行う以外は、クリックするのに1時間以上かかります。クエリはpyodbcインターフェイスを介してすべての化学物質のために働いているだけでなく、すべてが一度に機能するわけではありません。 –

答えて

2

残念ながら、MS Accessのを超えるシステムリソースは、実際のCPUリソース、ネットワーク環境、またはエンジンのパフォーマンスを損なう非効率なSQLクエリまたはVBAモジュールに関係する多少あいまいなメッセージです。

ただし、SQLを最適化できます。ウェルクエリでGROUP BYを使用して、DISTINCT句を集合クエリに置き換えることを検討してください。 DISTINCTは、ほとんどのRDMSで通常使用されるSQLパフォーマンスの低下であり、重複を除去するための完全な結果セットソートが必要です。さらに、DISTINCTが不十分なデータベース設計や計画プロセスを補うアドホック修正する傾向がある:他のエリアがエラーをトリガすべき

sql_string = """SELECT {0}.Well_ID, PSCODE, STAID, Status 
       FROM {0} 
       LEFT JOIN {1} ON {0}.Well_ID = {1}.Well_ID 
       WHERE STORE_NUM = ? 
       GROUP BY {0}.Well_ID, PSCODE, STAID, Status"""\ 
       .format(well_records_table_name, well_sites_table_name) 

、テーブルデザイン、クエリ処理のベストプラクティスを助けるかもしれません。したがって、複雑なネストされたサブクエリなどのその他の問題を確認してください。 WHEREおよびJOIN節の関数。非常に広いテーブル(1対多/多対多の関係で正規化するための記号)の使用。 Accessがロールバックのために結果セットのコピーを保存する(大抵2 GBのサイズに達する)大きなクエリのmake-table/append/updateのような大規模なトランザクション。

アクセスDBのヒント

  1. 膨満感を避けるために、データベースにクエリオプティマイザのための 統計をリフレッシュするためにたまにcompacting & repair を試してみてください。データベースは800 MBですが、操作中には のデータベースが展開されており、上記のような大規模なトランザクションではファイルの制限に達する可能性があります。
  2. プライマリ/コンポジットキーに加えて、テーブルでインデックスを使用します。テーブルデザインビューでは、フィールドプロパティセクションのインデックスとして個々のフィールドを選択するか、SQLのCREATE INDEXを使用できます。理想的には、このようなインデックスでテーブルを結合します。
  3. アクセス時にエンジンを実行する代わりに、Python SELECT * FROM Query1で名前付きオブジェクトの最適な計画と呼び出しを行うために、事前にコンパイルされ、最適化されたストアドクエリをAccessに保存します。これは、MS AccessのVBAクエリとストアドクエリの通常の議論です。計算に一時テーブルを使用するか、Pythonのpandasデータフレームに移行して分析してください。
  4. バックエンドデータベースを複数のデータベースに分割して、個々のファイルサイズを縮小してください。リコールアクセスは、SQL Server、Oracle、MySQLなどのサーバーレベルのRDMSでも、リンクされたテーブル(Pythonがアクセスできる)を使用して他のAccessファイルにリンクすることができます。
  5. テーブル列、クエリ結合、ファイル/テーブルサイズなど、常にAccess's limitationsを参考にしてください。結局のところ、アクセスはファイルレベルのRDMSであり、インフラストラクチャがオープンエンドのサーバーRDMSではありません。
+0

このエラーメッセージの問題は、多くの原因があるように見えるため、この回答を受け入れることになります。この回答はほとんどの原因に近づくための良い習慣を与えるようです。 –

+0

しかし、興味深いことに、 'GROUP BY'ヘルプは' DISTINCT clause'と比較してですか? – Parfait

+0

私の問題を何が解決したのか不思議な人たちのために、おそらくいろいろな変更がありました。私は、最大のものは、一度に1つのプロセスだけがデータベースから読み込むように、プログラムのフローを再設計していたと思います。これは残念なことに、アクセスからの読み取りが他のすべての操作と比較して遅いため、プログラムを非常に遅くします。ただし、接続が使用するリソースが制限されて問題が発生することはありません。私はまた、quiresを最適化し、接続とカーソルの最小量を使用して、いくつかの小さな変更を加えました。 –

関連する問題