現在、大規模な一括/バッチ インポート用に休止状態ベースのアプリでパフォーマンスとメモリ チューニングを行っています。基本的に、一部の製品が新規 (挿入) で一部が既存 (更新) の製品データを含む CSV ファイルをインポートしています。
私の焦点は、CSV ファイルの各行のチェック (存在する場合は選択) を行わずに、UPDATE するエンティティと INSERT するエンティティを見つけるための戦略を選択することです。
私の現在のアプローチは次のようなものです:
- データベース内のすべてのオブジェクトのハッシュマップを構築します。
- 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 に既に数千のエンティティがある場合に備えて、メモリ使用量をより細かく制御できます。
これについてあなたの考えは何ですか?どのエンティティを更新し、どのエンティティを一括で挿入するかを見つけるために、他にどのような効率的なアプローチがありますか?