0

MySQLデータベースを分析するアプリケーションを作成していますが、複数のDMLを同時に実行する必要があります。例えば:

// In ResultSet rsA: Select * from A;
rsA.beforeFirst();
while (rsA.next()) {
   id = rsA.getInt("id");
   // Retrieve data from table B: Select * from B where B.Id=" + id;
   // Crunch some numbers using the data from B
   // Close resultset B
}

それぞれがデータベースへの独自の接続を持つデータオブジェクトの配列を宣言しています。これにより、データ分析のためにいくつかのメソッドが呼び出されます。問題は、すべてのスレッドが同じ接続を使用するため、すべてのタスクが例外をスローすることです。「ロック待機タイムアウトを超えました。トランザクションを再開してみてください」

特定のオブジェクトが独自の接続を持ち、他のオブジェクトから独立して必要なタスクを実行するような方法でコードを記述する方法があると思います。例えば:

DataObject dataObject[0] = new DataObject(id[0]);
DataObject dataObject[1] = new DataObject(id[1]);
DataObject dataObject[2] = new DataObject(id[2]);
...
DataObject dataObject[N] = new DataObject(id[N]);
// The 'DataObject' class has its own connection to the database, 
// so each instance of the object should use its own connection. 
// It also has a "run" method, which contains all the tasks required.
Executor ex = Executors.newFixedThreadPool(10);

for(i=0;i<=N;i++) {
   ex.execute(dataObject[i]);
}
// Here where the problem is: Each instance creates a new connection,
// but every DML from any of the objects is cluttered in just one connection
// (in MySQL command line, "SHOW PROCESSLIST;" throws every connection, and all but
// one are idle).

私を正しい方向に向けてもらえますか?

ありがとう

4

2 に答える 2

1

問題は、多くの中間層、トランザクション、および永続ロジックを1つのクラスに混同していることだと思います。

ResultSetを直接扱っている場合は、オブジェクト指向の方法で物事を考えているわけではありません。

データベースに計算の一部を実行させる方法を理解できれば、賢明です。

そうでない場合は、可能な限り最小限の時間、接続を開いたままにしておくことをお勧めします。接続を開き、ResultSetを取得し、それをオブジェクトまたはデータ構造にマップし、ローカルスコープのResultSetとConnectionを閉じて、マップされたオブジェクト/データ構造を処理のために返します。

このようにして、永続性と処理ロジックを分離します。接続を短命に保つことで、多くの悲しみを救うことができます。

ストアドプロシージャソリューションが遅い場合は、インデックス作成が不十分である可能性があります。別のソリューションは、悪くはないにしても、同様にパフォーマンスが低下します。EXPLAIN PLANを実行して、クエリのいずれかがTABLESCANを使用しているかどうかを確認してください。はいの場合、追加するインデックスがいくつかあります。トランザクションが長時間実行されている場合は、ロールバックログが大きいことが原因である可能性もあります。切り替える前に、使用しているソリューションで可能なすべてのことを確実に実行するために、できることとすべきことはたくさんあります。多大な労力を費やしても、根本的な原因に対処できない可能性があります。

于 2010-06-01T23:23:32.467 に答える
0

しばらく頭を悩ませた後、自分の過ちを見つけました...この新しい知識を入れたいので...ここに行きます

コードでConnectionオブジェクトを静的オブジェクトとして宣言することで非常に大きな間違いを犯しました...したがって、作成した新しいデータオブジェクトごとに新しいConnectionを作成したにもかかわらず、すべてのトランザクションは単一の静的接続を通過しました。

その最初の問題が修正されたので、私は設計テーブルに戻り、私のプロセスが次のとおりであることに気づきました。

  1. 入力テーブルからIDを読み取ります
  2. 手順1で読み取ったIDに関連するデータのブロックを取得し、他の入力テーブルに保存します
  3. クランチ番号:関連する入力テーブルを読み取り、それらに格納されているデータを処理します
  4. 結果を1つ以上の出力テーブルに保存します
  5. 入力テーブルに保留中のIDがある間、このプロセスを繰り返します

入力読み取り専用接続と出力書き込み専用接続を使用するだけで、プログラムのパフォーマンスが向上しました...しかし、もっと多くのことが必要でした!

ステップ3と4の元々のアプローチは、結果を取得したらすぐにそれぞれの結果を出力に保存することでした...しかし、より良いアプローチを見つけました。

  • 入力データを読み取る
  • 数値を計算し、結果を一連のキューに入れます(出力テーブルごとに1つ)
  • 分離されたスレッドは、キューのいずれかにデータがあるかどうかを毎秒チェックしています。キューにデータがある場合は、それをテーブルに書き込みます。

したがって、異なる接続を使用して入力タスクと出力タスクを分割し、コアプロセスの出力をキューにリダイレクトし、出力ストレージタスク専用のスレッドを使用することで、最終的に目的のマルチスレッドDML実行を実現しました。


この特定の問題にはもっと良いアプローチがあることを私は知っていますが、これは非常にうまく機能します。

だから...誰かがこのような問題で立ち往生しているなら...私はこれが役立つことを願っています。

于 2011-03-28T17:33:37.670 に答える