0

Java と Hibernate の JPA 実装を使用してデータベース Web アプリケーションを構築しています。アプリケーションはオブジェクトを追跡します。また、レガシー ソースからオブジェクトをバッチ インポートする必要があります。

たとえば、人を追跡しているとしましょう。データベースには、Person および Address というテーブルがあります。対応する JPA エンティティと DAO クラスがあります。

JPAレイヤーの上には、さまざまな操作を担当するサービスレイヤーがあります。1 つの操作は、外部のレガシー ソース (電話帳の人など) から潜在的に大きなデータ セットをインポートすることです。人ごとに、データベースに既に存在するかどうかを確認する必要があります。次に、必要に応じて人物を作成または更新する必要があります。各人は住所を持っているため、適切な相互参照と住所の作成も行う必要があります。

私の問題は、この操作が大きなデータ セットに対して遅くなる可能性があることです。私の現在のアルゴリズムは次のとおりです。

for (Person person: allPersons)
{
    check if person exists in database
    check if address exists in database
    create or update person and address as necessary
}

パフォーマンスを向上させるために何をお勧めしますか?

頭のてっぺんから次のことを考えることができます:

  1. クエリを使用してデータを取得し、データベースに保存するようにインポート ロジックを変更します。たとえば、人が for ループ内に存在するかどうかを確認する代わりに、すべての人のキーを 1 つのクエリでデータベースに送信します。各プロセスはメモリ内の人を取得します。
  2. DAO クラスに独自のキャッシュを追加します。
  3. 外部キャッシュ ソリューション (memcached など) を使用します。

クエリを最小限に抑えるために再構築することで、常に#1を使用できます。欠点は、サービス層が DAO 層を非常に認識していることです。その実装は、下位のデータベース層によって決定されるようになりました。メモリの使用量が多すぎるなどの問題もあります。このデータベースから取得してからメモリ内で処理する方法は、非常に自家製のようであり、JPA のような市販のソリューションに反します。この場合、他の人がどうするか興味があります。

編集:ループ内でクエリされる各人が異なるため、キャッシュは役に立ちません。

4

2 に答える 2

1

私がその仕事を見つけた2つの解決策があります。1つは、一度にチャンクを処理することです。各チャンクが閉じた後、セッションを再開します。セッションでflushclearメソッドを使用しようとしましたが、期待どおりに機能する場合があります。バッチ間のトランザクションの開始と停止が最も効果的であるようです。

パフォーマンスが主要な懸念事項である場合は、JDBCで分解して実行するだけです。Hibernateは、メモリとパフォーマンスが重要な大規模なデータセットのバッチ処理にオーバーヘッドを追加しすぎます。

于 2008-12-23T03:46:28.600 に答える
0

あなたのアプローチは、データベースに対する個々のクエリが多すぎるという結果になります。4n + 1 のように見えます。可能であれば、一発で person + address の存在をチェックするクエリを (おそらく生の SQL で) 書きたいと思います。

標準の Hibernate セッションの代わりに StatelessSession を使用したい場合があります。第 1 レベルのキャッシュがないため、メモリ要件を低く抑える必要があります。

http://www.hibernate.org/hib_docs/reference/en/html/batch-statelesssession.html

それがうまくいかない場合は、Hibernate のバッチ オプションを確認してください。

http://www.hibernate.org/hib_docs/reference/en/html/batch.html

于 2009-01-01T06:10:58.020 に答える