5

現在、大規模な一括/バッチ インポート用に休止状態ベースのアプリでパフォーマンスとメモリ チューニングを行っています。基本的に、一部の製品が新規 (挿入) で一部が既存 (更新) の製品データを含む CSV ファイルをインポートしています。

私の焦点は、CSV ファイルの各行のチェック (存在する場合は選択) を行わずに、UPDATE するエンティティと INSERT するエンティティを見つけるための戦略を選択することです。

私の現在のアプローチは次のようなものです:

  1. データベース内のすべてのオブジェクトのハッシュマップを構築します。
  2. CSV を繰り返し処理し、ハッシュマップを使用して更新するか挿入するかを決定します。

このアプローチはうまく機能し、すべての行に対してこのような単一の IF EXISTS チェックを実行するよりもはるかに高速であることがテストで証明されています。

DBにエンティティがたくさんある場合、私の懸念はメモリサイズです。

現在、上記のアプローチのわずかなバリエーションを使用することを考えており、意見を知りたい. 基本的に私がやりたいことは、複数の行で IF EXISTS チェックの複数のバッチを実行することです (例SELECT FROM table where sku IN (sku1, sku2, sku3))

ここにいくつかの擬似コードがあります:

1. Database contains: db{sku1, sku2,sku3,sku5}

2. file contains: file {sku1, sku2, sku3, sku6}

3. Expected result: 
   updates: {sku1, sku2, sku3}
   inserts{sku6}

4. Algorithm

   have a map to keep database entities which need updates
   updatemap {}
   now iterate over the file in e.g. batches of 2 rows (for demo purposes)
   1st iteration: foreach (select where sku IN (sku1, sku2) limit 2) as elem
    -> updatemap.add(elem)  -> elem is asumed to be a persistent entity here
    -> myDAO.update(elem)   -> executes Spring's getHibernateTemplate().update() under the hood

   -> updatemap contents after 1st loop {sku1, sku2}

   2nd iteration: foreach (select where sku IN (sku3, sku6) limit) 2 as elem
    -> updatemap.add(elem)    
    -> myDAO.update(elem)

   -> updatemap contents after 3nd loop {sku1, sku2, sku3}

ところで:私はすでに次のようなものも想定しています(if i % 30 == 0) session.flush; session.clear();

これで、更新されたすべての要素がわかります。updatemap にないすべての sku は基本的に挿入であり、単純な集合演算を使用してそれらを決定できます。

ファイル {sku1、sku2、sku3、sku6} - updatemap {sku1、sku2、sku3} = newinserts {sku6}

これで、残りの CSV 行に対して挿入を行うことができます。

結論 私の推測では、ファイル コンテンツのチャンク化により、使用するメモリ量を制限できると思います。最初のアプローチよりも多くの SELECT ステートメントがありますが、DB に既に数千のエンティティがある場合に備えて、メモリ使用量をより細かく制御できます。

これについてあなたの考えは何ですか?どのエンティティを更新し、どのエンティティを一括で挿入するかを見つけるために、他にどのような効率的なアプローチがありますか?

4

2 に答える 2

2

私は何百万ものレコードを含むまったく同じ問題を抱えていて、あなたとほとんど同じように解決しました。サイドオブザーバーには明らかではないかもしれない制約は、通常の Hibernate の load-mutate-update の方法を使用できないことです。これは、過度の量の冗長トラフィックが作成されるためです。

よく読むと、私のアプローチは、単一のチャンクの処理を超えて情報を保持しないという点で、あなたのアプローチとは異なります。次のチャンクに進む前に、すべての挿入と更新を含め、チャンクを完全に処理します。そうすることによってのみ、スケーラブルなソリューションを実現できます。

私にとって最も弱い点はexecuteUpdate、JDBC バッチ API を使用しない の使用です。executeUpdateカスタム実装を作成する予定でしたが、特定のユース ケースでは、チャンクごとに複数使用する必要がないことがわかりました。

于 2012-08-26T17:28:11.060 に答える
0

私の考え

1)これを行うとき SELECT FROM table where sku IN (sku1, sku2, sku3) )

sku が見つからない場合、各クエリは完全なテーブル スキャンを実行する可能性があり、n 回のパスで残りのエンティティに対してこれを実行すると、最悪の場合、n * テーブル スキャンが必要になる可能性があります。

おそらく、より簡単なアプローチは、csv 内のすべてのエンティティに対して重複するテーブルを作成することです (sku の列は 1 つだけで、MINUS を実行して新しい sku を挿入することができます)。

 select sku from dup_table
  MINUS  //(EXCEPT for Mysql)
 select sku from table`

これらのレコードを新しいテーブル (dup_table2) に保存し、dup_table で別の MINUS を実行すると、sku が更新されます。しかし、これらの演算子はデータベース固有のものであり、パフォーマンスがどの程度向上するかはわかりません。しかし、IMHOは句よりもはるかに優れたオプションに見えますwhere in(特にcsvリストが大きくなった場合)

于 2012-08-26T19:04:32.230 に答える