回答:
ハッシュ結合とハッシュ集計はどちらも内部的に同じ演算子コードを使用しますが、ハッシュ集計は単一の(ビルド)入力のみを使用します。基本的な操作ハッシュ集計がされクレイグ・フリードマンによって記述します:
ハッシュ結合と同様に、ハッシュ集計にはメモリが必要です。SQL Serverは、ハッシュ集計を使用してクエリを実行する前に、基数の見積もりを使用して、クエリを実行するために必要なメモリの量を見積もります。ハッシュ結合では、各ビルド行を保存するため、合計メモリ要件はビルド行の数とサイズに比例します。結合する行の数と結合の出力カーディナリティは、結合のメモリ要件に影響を与えません。ハッシュ集計では、グループごとに1行を格納するため、合計メモリ要件は実際には出力グループまたは行の数とサイズに比例します。列ごとのグループの一意の値が少なく、グループが少ない場合、必要なメモリは少なくなります。列ごとのグループの固有の値とグループが多い場合は、より多くのメモリが必要です。
彼はさらにハッシュ再帰について話します:
では、メモリが不足するとどうなりますか?繰り返しになりますが、ハッシュ結合と同様に、メモリが不足した場合は、tempdbに行を書き出す必要があります。1つ以上のバケットまたはパーティションをスピルし、部分的に集計された結果と、スピルしたバケットまたはパーティションにハッシュする新しい行を追加します。あふれた新しい行を集約することは試みませんが、それらをハッシュして複数のバケットまたはパーティションに分割します。すべての入力グループの処理が終了したら、完成したメモリ内グループを出力し、こぼれたパーティションを一度に1つずつ読み取って集計することにより、アルゴリズムを繰り返します。こぼれた行を複数のパーティションに分割することにより、各パーティションのサイズを縮小し、アルゴリズムが何度も繰り返す必要があるリスクを低減します。
ハッシュの救済は簡単に文書化されていますが、救済を強制する前のハッシュイテレータの再帰の最大レベルは何ですか?で Nacho Alonso Portilloによって言及されました。
値は定数であり、製品にハードコードされており、その値は5です。これは、ハッシュスキャンオペレーターが、ワークスペースからの許可されたメモリに収まらない特定のサブパーティションのソートベースのアルゴリズムに頼る前に、元のパーティションをより小さなパーティションに分割する前の5回の試行が行われている必要があることを意味します。
「ハッシュスキャンオペレータは、」内部クラスへの参照がある言及CQScanHash
ではsqlmin.dll
。このクラスは、実行計画で見られるハッシュ演算子(部分的な集計やフローの区別を含むすべての形式)の実装の先頭に立っています。
これは私たちをあなたの質問の核心に導きます-救済アルゴリズムは正確に何をしますか?それは「ソートベース」ですか、それとも「一種の入れ子ループ」に基づいていますか?
それは、あなたの視点に応じて、間違いなく両方です。ハッシュの再帰がレベル5に達すると、メモリ内のハッシュパーティションは、ハッシュテーブルから、ハッシュ値の最初は空のbツリーインデックスに変わります。以前に流出した単一のハッシュパーティションからの各行は、Bツリーインデックスで検索され、必要に応じて挿入(新しいグループ)または更新(集約の維持)されます。
Bツリーへのこの一連の順序付けられていない挿入は、挿入ソートとして、またはインデックス付きのネストされたループのルックアップとしても同様に見ることができます。
いずれの場合でも、このフォールバックアルゴリズムは、メモリを割り当てずに最終的に完了することが保証されています。bツリーに使用可能なスペースがオーバーフローパーティションからのすべてのグループ化キーと集約を保持するのに十分でない場合は、複数のパスが必要になる場合があります。
Bツリーインデックスを保持するために利用可能なメモリが使い果たされると、(現在のスピルパーティションから)それ以上の行が単一の新しいtempdbパーティション(サイズが小さいことが保証されています)に送信され、プロセスは必要に応じて繰り返されます。ハッシュの再帰が終了したため、流出レベルは5のままです。いくつかの処理の詳細は、文書化されていないトレースフラグ7357で確認できます。