2016-10-11 10 views
1

私は以下の作業を行います:すべてのアクティブなアカウントの利子を計算します。過去に私はAdo.Netとストアドプロシージャを使ってこのようなことをしていました。 今度は、純粋なPOCOで複雑なアルゴリズムを簡単に実行できるように見えるので、NHibernateでこれをやろうとしました。 次のようにしたい(擬似コード): foreach account in accounts calculate interest save account with new interest NHibernateは大量のデータを処理するようには設計されていません。私にとっては、一度にすべてのアカウントをメモリに入れなくても、このようなループを構成することができれば十分です。 メモリの使用量を最小限に抑えるために、私はの代わりにIStatelessSessionを外部ループに使用します。 私はAyendeが提案したアプローチを試みました。 2つの問題があります。NHibernateで大きな結果セットを処理する

  • CreateQueryは "magic strings"を使用しています。
  • より重要:説明どおりに動作しません。

私のプログラムは動作しますが、ODBCトレースをオンにした後、私はすべてのフェッチが初めて実行された.Listにラムダ式の前に行われたデバッガで見ました。 私は自分自身が別の解決策を見つけました:session.Query foreachで使った.AsEnumerable()を返します。再び二つの問題:

  • 私はまだ(すべては最初の利息計算の前にフェッチ)説明したように動作しないのIQueryable
  • 上IQueryOverを好むだろう。

IQueryOverにはAsEnumerableが含まれていない理由がわかりません。また、引数を持つListメソッド(CreateQueryなど)もありません。私は再び.Futureを試みたが、しました:未来の

  • ドキュメントは、私は(すべてが最初の利息計算の前にフェッチ)必要があるとして、まだ動作しませんストリーミング機能
  • を説明していません。

要約:NHibernateには、Ado.NetのdataReader.Read()に相当するものがありますか?

NHibernateの純粋なアプローチの代わりに、dataReader.Read()を使用するメインループと、Ado.NetループのIDを持つLoadアカウントを使用します。ただし、キーを使用して各アカウントを読み取ることは、外部ループで行われるフェッチのシーケンスよりも遅いです。

NHibernateバージョン4.0.0.4000を使用しています。

+0

すべての更新を1回のトランザクションで行うことはできますが、最初にすべてのアカウントを取得してから変更を加え、1回のバッチコールでemを保存する必要があります。私は前に同様の問題に対処しようとしましたが、私の最大の問題は通常、SQLプロファイラを使用すると見つけやすいselect-n問題を扱っていました –

+0

データベーストランザクションは私にとって問題ではありません。すべてのアカウントまたは各アカウントごとに1つのトランザクションにすることができます。私の心配はメモリ消費に関係しています。私は生産システム(約1 mlnのアカウント)ですべてのアカウントをすぐにメモリに取り込むことができるかどうかはわかりません。 – robsosno

+0

また、Jaguarによれば、メモリ内のオブジェクトの数があるしきい値を超えたときにパフォーマンスが低下します。 – robsosno

答えて

1

NHは大量の処理を考慮して設計されていないことは念頭に置いていますが、アプリケーション層のバッチ処理ではこの制限を常に回避できます。私は、関連するエンティティのオブジェクトグラフのサイズに応じて、ある量のオブジェクトがメモリにロードされた後にパフォーマンスが低下することが分かっています(小さなプロジェクトでは100,000個のオブジェクトをロードでき、パフォーマンスは許容できます。追加のLoad()がクロールするオブジェクトは1500個しかありません)。

これまでは、IStatelessSessionの結果セットが(プロキシなどをロードしないので)貧弱すぎるときに、バッチ処理を処理するためにページングを使用していました。

最初にカウントクエリを作成し、任意のバッチサイズを作成して、バッチ処理を開始します。この方法では、明示的にフェッチする各バッチに対して、必要なすべてを結合すると仮定すると、n + 1選択問題をきちんと回避できます。

これが効率的に機能するためには、完了した時点で、各バッチの処理済みエンティティをセッションから退去させる必要があります。これは、各バッチでトランザクションをコミットする必要があることを意味します。あなたが複数のフラッシュ+コミットで暮らすことができるなら、これはあなたのために働くことができます。

これ以外の場合は、怠け者のクエリはありませんが、IStatelessSessionを実行する必要があります。 "Booksから"とは、 "select * from dbo.Books"か同等のものを意味し、すべての結果がメモリに取り込まれます。

+0

OK、ジョブ全体をバッチに分割するのが良い解決策です。私はしばらくお待ちしています。多分、仕事の分割なしにそれをする解決策があります。 – robsosno

+0

n + 1の問題については、後でこれを戦うつもりです。現在、アカウント処理に関する詳細はありません。アカウントの残高を1ずつ増やし、時間とメモリ消費量を観察して、シミュレーション処理を行っています。 – robsosno

関連する問題