Rettungspaket für Hash-Aggregate


Antworten:


11

Hash-Join und Hash-Aggregat verwenden intern denselben Operatorcode, obwohl ein Hash-Aggregat nur eine einzige (Build-) Eingabe verwendet. Die grundlegende Funktionsweise des Hash-Aggregats wird von Craig Freedman beschrieben :

Wie beim Hash-Join benötigt das Hash-Aggregat Speicher. Vor dem Ausführen einer Abfrage mit einem Hash-Aggregat verwendet SQL Server Kardinalitätsschätzungen, um zu schätzen, wie viel Speicher wir zum Ausführen der Abfrage benötigen. Bei einem Hash-Join speichern wir jede Build-Zeile, sodass der gesamte Speicherbedarf proportional zur Anzahl und Größe der Build-Zeilen ist. Die Anzahl der zu verbindenden Zeilen und die Ausgabekardinalität des Joins haben keinen Einfluss auf den Speicherbedarf des Joins. Bei einem Hash-Aggregat speichern wir eine Zeile für jede Gruppe, sodass der Gesamtspeicherbedarf tatsächlich proportional zur Anzahl und Größe der Ausgabegruppen oder Zeilen ist. Wenn wir weniger eindeutige Werte der Gruppe nach Spalte (n) und weniger Gruppen haben, benötigen wir weniger Speicher. Wenn wir mehr eindeutige Werte der Gruppe nach Spalte (n) und mehr Gruppen haben, benötigen wir mehr Speicher.

Er spricht weiter über Hash-Rekursion:

Was passiert also, wenn uns der Speicher ausgeht? Wie bei einem Hash-Join müssen wir auch hier anfangen, Zeilen an Tempdb zu verschütten, wenn uns der Speicher ausgeht. Wir verschütten einen oder mehrere Buckets oder Partitionen, einschließlich teilweise aggregierter Ergebnisse, zusammen mit zusätzlichen neuen Zeilen, die auf die verschütteten Buckets oder Partitionen gehasht werden. Obwohl wir nicht versuchen, die verschütteten neuen Zeilen zu aggregieren, hashen wir sie und teilen sie in mehrere Buckets oder Partitionen auf. Sobald wir alle Eingabegruppen verarbeitet haben, geben wir die abgeschlossenen In-Memory-Gruppen aus und wiederholen den Algorithmus, indem wir jeweils eine verschüttete Partition zurücklesen und aggregieren. Durch die Aufteilung der verschütteten Zeilen in mehrere Partitionen reduzieren wir die Größe jeder Partition und damit das Risiko, dass der Algorithmus viele Male wiederholt werden muss.

Rettungsaktion

Das Hash-Bailout ist leicht dokumentiert, wird jedoch von Nacho Alonso Portillo in Was ist die maximale Rekursionsstufe für den Hash-Iterator vor dem Erzwingen des Bail-Outs erwähnt?

Der Wert ist eine Konstante, die im Produkt fest codiert ist, und sein Wert beträgt fünf (5). Dies bedeutet, dass fünf vorherige Versuche, die ursprüngliche Partition in kleinere Partitionen zu unterteilen, stattgefunden haben müssen, bevor der Hash-Scan-Operator für eine bestimmte Unterpartition, die nicht in den gewährten Speicher des Arbeitsbereichs passt, auf einen sortierungsbasierten Algorithmus zurückgreift.

Der dort erwähnte "Hash-Scan-Operator" verweist auf die interne Klasse CQScanHashin sqlmin.dll. Diese Klasse leitet die Implementierung des Hash-Operators (in all seinen Formen, einschließlich Teilaggregaten und Flussunterschieden), die wir in Ausführungsplänen sehen.

Bailout-Algorithmus

Dies bringt uns zum Kern Ihrer Fragen - was genau macht der Rettungsalgorithmus? Ist es "sortbasiert" oder basiert es auf "einer Art verschachtelter Schleifen"?

Es ist wohl beides, abhängig von Ihrer Sichtweise. Wenn die Hash-Rekursion Stufe 5 erreicht, ändert sich die speicherinterne Hash-Partition von einer Hash-Tabelle zu einem anfänglich leeren B-Tree-Index für die Hash-Werte. Jede Zeile einer einzelnen zuvor verschütteten Hash-Partition wird im B-Tree-Index nachgeschlagen und entsprechend eingefügt (neue Gruppe) oder aktualisiert (Aggregate beibehalten).

Diese Reihe von ungeordneten Einfügungen in einen B-Baum kann ebenso gut als Einfügungssortierung oder als Suche nach indizierten verschachtelten Schleifen angesehen werden.

In jedem Fall wird garantiert, dass dieser Fallback-Algorithmus irgendwann abgeschlossen wird, ohne mehr Speicher zuzuweisen. Es können mehrere Durchgänge erforderlich sein, wenn der für den B-Baum verfügbare Speicherplatz nicht ausreicht, um alle Gruppierungsschlüssel und Aggregate von der Überlaufpartition aufzunehmen.

Sobald der für den B-Tree-Index verfügbare Speicher erschöpft ist, werden alle weiteren Zeilen (von der aktuell verschütteten Partition) an eine einzelne neue Tempdb- Partition (die garantiert kleiner ist) gesendet, und der Vorgang wird nach Bedarf wiederholt. Das Überlaufniveau bleibt bei 5, da die Hash- Rekursion beendet ist. Einige Verarbeitungsdetails können mit dem undokumentierten Ablaufverfolgungsflag 7357 beobachtet werden.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.