私の質問は、SQL Serverは、利用可能なスペースよりも多くのデータをバッファキャッシュにプルする必要があるクエリをどのように処理するのですか?このクエリには複数の結合が含まれるため、結果セットはすでにディスク上にこの形式で存在しておらず、結果をコンパイルする必要があります。ただし、コンパイル後でも、バッファキャッシュで使用可能な領域よりも多くの領域が必要です。
例を挙げましょう。合計6GBの利用可能なバッファキャッシュスペースを持つSQL Serverインスタンスがあるとします。 7GBのデータを読み取る複数の結合を使用してクエリを実行しますが、SQL Serverはこの要求にどのように応答できますか? tempdbにデータを一時的に保存しますか?失敗しますか?ディスクからデータを読み取り、一度にセグメントをコンパイルするだけですか?
さらに、7GBの合計データを返そうとするとどうなりますか?SQL Serverがデータを処理する方法は変わりますか?
私はこれに対処するいくつかの方法をすでに知っていますが、SQL Serverが前述のように実行されたときに、SQL Serverがこの要求を内部的に処理する方法に興味があります。
また、この情報はどこかにあると思いますが、見つけることに失敗しました。
必要に応じてページがメモリに読み込まれ、使用可能な空きメモリがない場合は、変更されていない最も古いページが着信ページに置き換えられます。
つまり、メモリに収まらないほど多くのデータを必要とするクエリを実行すると、多くのページでメモリの寿命が非常に短くなり、大量のI/Oが発生します。
この効果は、Windowsパフォーマンスモニターの "Page Life Expectancy"カウンターで確認できます。そのカウンターの詳細については、 https://sqlperformance.com/2014/10/sql-performance/knee-jerk-page-life-expectancy を参照してください。
コメントでは、クエリのresultsが使用可能なバッファスペースよりも大きい場合にどうなるかを具体的に尋ねました。最も単純な例として、_select * from some_very_big_table;
_-テーブルが32GBであり、max server memory (MB)
が24GBに設定されていると仮定します。すべての32GBのテーブルデータは、一度に1つずつページバッファーのページに読み込まれ、 ラッチ 、ネットワークパケットにフォーマットされ、ネットワーク経由で送信されます。これはページごとに発生します。このようなクエリを同時に300個実行することができ、ブロッキングが発生していないと仮定すると、各クエリのデータは、ページバッファスペースに一度に1ページずつ読み込まれ、クライアントができる限り速くネットワークに送信されます。データをリクエストして使用します。各ページのすべてのデータがネットワークに送信されると、ページのラッチが解除され、すぐにディスクの他のページに置き換えられます。
より複雑なクエリの場合、たとえば複数のテーブルからの結果を集計する場合など、ページはクエリプロセッサが必要とするため、上記とまったく同じようにメモリに読み込まれます。クエリプロセッサが結果を計算するために一時的なワークスペースを必要とする場合、クエリのプランをコンパイルするときにそのことを事前に認識し、ワークスペース(メモリ)を [〜#〜] sqlos [〜#〜]に要求します 。 SQLOSはある時点で(それが time out でないと仮定して)、そのメモリをクエリプロセッサに許可し、その時点でクエリ処理が再開されます。クエリプロセッサがSQLOSに要求するメモリ量の見積もりを間違えた場合、データが中間のtempdbに一時的に書き込まれる "spill to disk" 操作を実行する必要がある場合があります。形。 tempdbに書き込まれたページは、tempdbに書き込まれるとラッチ解除され、他のページをメモリに読み込むためのスペースが確保されます。最終的に、クエリプロセスはtempdbに格納されているデータに戻り、ラッチを使用してページングされ、空き領域としてマークされているバッファー内のページに戻ります。
上記の要約では、非常に多くの技術的な詳細が欠落していることは間違いありませんが、SQL Serverがメモリに収まりきらないデータを処理する方法の本質を捉えていると思います。
このシナリオでクエリが正確に何を行うかについて話すことはできませんが、SQL Serverには必要な量に応じていくつかのオプションがあります。
何が起こるかを知る最善の方法は、開発環境でシナリオを作成して調べることです。
私の質問は、SQL Serverが、より多くのデータ量をバッファキャッシュにプルする必要があるクエリをどのように処理するかです。
この特定の部分に答えるために、これがどのように管理されているかを説明しましょう。ページのサイズは8KBです。大規模なデータセットを要求するクエリを実行すると、メモリに多数のページを取り込む必要がある場合、SQL Serverはすべてのページを一度にしない。それは特定のページを見つけてメモリに1つずつ8KBページを持ち込み、そこからデータを読み取り、結果を提供します。これは、古いページがフラッシュされる場合にメモリが少ない状況に直面していると想定します。 @Maxのようなディスクが指摘しました。あなたが正しく推測したように、この低いメモリは古いページの削除にいくらかの時間が費やされるため、物事を遅くする可能性があります。これが チェックポイントとレイジーライター の登場です。 Lazywriterは、新しいページをディスクに取り込むために、常に空きメモリがあることを確認するためのものです。空きバッファが不足すると、それがトリガーされ、新しいページになる空きスペースが作成されます。
[〜#〜]編集[〜#〜]
私はそれを理解しましたが、\ filteringデータを結合していて、それらの結果がキャッシュのサイズを超えた場合に、私を少し困惑させる部分が起こります。
結合とフィルタリングのためのメモリは、クエリが実行される前でも決定され、実際にメモリ不足があり、操作の実行に必要なメモリが利用できないと仮定します。SQLServerプロセッサは、「必要なメモリ」を付与します。
必要なメモリ:ソートとハッシュ結合の実行に必要な最小メモリ。このメモリがないとクエリが開始されないため、必須と呼ばれます。 SQLサーバーは、このメモリを使用して内部データ構造を作成し、並べ替えとハッシュ結合を処理します。
したがって、少なくともクエリは実行を開始しますが、実行時に中間結果がTempdbに流出し、処理が遅くなる可能性があります。 クエリメモリ許可について を読むことを強くお勧めします