web-dev-qa-db-ja.com

単一のデータベース呼び出しとメモリ内での反復vs複数のデータベース呼び出しと複数の小さな反復

私は非常に基本的な新しいアプリケーションを設計していますが、それが成長することを期待しており、将来的にリファクタリングする必要はありません。私の課題は、1つの方法で、データベースから数千(たとえば20,000)のレコードを取得してメモリ内でそれらを反復処理するか、ループで複数の呼び出し(たとえば、それぞれ100レコードに対して200リクエスト)を行う必要があることです。

私は this 同様の質問を見ました。「データベース呼び出しが少ないほど良い」という考え方に基づいています。 Windowsアプリケーションで繰り返してはいけないアイテムの数に上限はありますか?このアプローチは、パフォーマンスの利点を無効にする可能性があるメモリの問題になりやすいでしょうか?

これは特定のシナリオに限定されるものではなく、私は以前にこの考えを持っていて、後者のオプション(小さいデータセットに対する複数のリクエスト)を選択しました。

私はこれを考えすぎていますか?

1
Daniel

「データベースが少ないほど良い呼び出し」は明らかに偽りです。その場合、推奨される手法は、アプリケーションの起動時にデータベースの膨大なセクションをアプリケーションに読み込み、ほとんどの処理をメモリ内で実行することですが、ほとんどのアプリケーションはそのように設計されていません。

したがって、最適なパスを見つけることが重要です。ほとんどの場合、その方法はパフォーマンスを測定することです。どのアプローチが最適か(速度、ネットワーク遅延、メモリ使用量の観点から)調べ、それを実行します。 。

特定の例では、オプションである場合、データベースサーバーで処理を行うことにより、ネットワークトラフィックと遅延のほとんどを回避できます。 SQLステートメントを記述して、処理のためにそれらのレコードのすべてをネットワーク経由で転送せずに結果を取得できるシナリオはたくさんあります。

6
Robert Harvey

一般に、SQL呼び出しをループ内に置くことは、実行できる最も遅い処理の1つです。

最初にすべてのデータを取得してからループする方が常に高速です。明らかな制限は、アプリを実行しているコンピューターの使用可能なメモリです。

これは通常、SQLをいくつかのより大きな選択に調整するだけで実現できます。例えば

select from parent where x
foreach parent
    select from child where parentid=y
next

select from parent left join child where x
foreach row
    if parentid != last parentId
          new parent
    new child
next

または、ループの前に2つのselectを持つバリアントで、すべての子をハッシュマップに入れてすばやく検索できます。結果をキャッシュしている場合は、間違いなくどちらが良いでしょう。

私はそのようなリポジトリの使用を提唱します。

var parents = repo.GetParentsWhereX(x)
var children = repo.GetChildernForParentsWithX(x)
foreach parent....

これにより、結合されたテーブルオブジェクトを回避しながら、ほとんどのパフォーマンスが得られます。

これらの種類の選択で、処理するにはデータが多すぎる場合は、ページングされたクエリに移動できます。しかし、一般的に私はマイクロ最適化を見つけ、バルクデータエクスポートのようなものがある場合にのみそれを使用します。

1
Ewan