web-dev-qa-db-ja.com

ループ内のデータベースからクエリを実行することは悪い習慣ですか?

まず、私はまだ可能な限りのベストプラクティスで物事を行うことを学んでいます。データベースクエリを処理する際のベストプラクティスを教えてください。ループ内でクエリを実行して、そのデータが存在するかどうかを確認するコードを見てきました。それでは、以下に示す一連のコードがあるとします。

// assume that institutions are the list of institutionids
foreach(var institution in institutions)
{
    // get here the project for an institution.
    var projects = _projectRepository.GetForInstutition(institution);

    // do sets of commands here...
}

データに対して何かを行う前に、データベースから必要なすべてのデータに対してクエリを実行する方がよいのはなぜですか?これについてもっと理解したいと思います。

6
rpmansion

これはメモリ階層の場合であり、最も効率的な方法を指示します。

通常、コンピューターにはさまざまなタイプのストレージがあります。最大のものも最も遅いものです。 CPUレジスタはすべての中で最も高速ですが、最小でもあります。オンチップキャッシュは大きくなりますが低速ですが、セカンドレベルキャッシュはさらに大きくなります。RAMはさらに大きく、大容量記憶装置(ハードドライブなど))はさらに大きく、ネットワークデバイスのサイズは基本的に無制限です。

通常、アクセス速度の違いは劇的です。データベースは、ハードディスクに似ているか、ネットワークアクセスに似ているかによって異なりますが、ほとんどの場合、RAMとの間でデータを移動するよりも遅くなります。通常、接続を開いてクエリを送信するだけでも非常に時間がかかるため、メモリ内で何十億もの操作を同時に実行できた可能性があります。

したがって、すべての結果がRAMに収まることが期待される限り、通常はoneデータベースクエリを実行して、必要なすべてのデータを取得してから、クエリ、処理、クエリを再度実行するよりも操作を開始します。 、再処理など。ループを完了するために必要な全体の時間を劇的に短縮します。

4
Kilian Foth

これは古典的な 時空のトレードオフ です

もちろん、次のようにすべてをコンピュータのメモリに吸い込むことができます。

var projectMap = _projectRepository.GetForInstutitions(institutions);
foreach(var institution in institutions)
{
    var projects = projectMap.get(institution);

    // do sets of commands here...

}

これを slurping と呼びます。あなたはすでに代替案を投稿しました: chuncking 。丸呑みは、チャンク処理よりもデータベースへのリクエスト数を減らします。しかし、それはあなたのコンピュータのメモリに何をするのでしょうか?まあそれはあなたがどれだけ大きく、どれだけあなたがメモリに吸い込まれているかに依存します。十分に引き込むと、キャッシュミスのためにOSがメモリをページファイルにスワップするときに、突然ハードドライブを叩きます。

これが本当に問題かどうかを確認するには、このようなものをテストする必要があります。どちらの極端な場合でも失敗する可能性があります。重要なのは、バランスを見つけることです。

3
candied_orange