Plan de sauvetage global de hachage

10

Une question qui a surgi lors d'une discussion par clavardage:

Je sais que le hachage rejoint les commutateurs de sauvetage en interne pour une sorte de boucle imbriquée.

Que fait SQL Server pour un sauvetage d' agrégat de hachage (si cela peut arriver)?

Paul White 9
la source

Réponses:

11

La jointure par hachage et l' agrégat de hachage utilisent tous les deux le même code opérateur en interne, bien qu'un agrégat de hachage n'utilise qu'une seule entrée (build). Le fonctionnement de base de l' agrégat de hachage est décrit par Craig Freedman :

Comme pour la jointure par hachage, l'agrégat de hachage nécessite de la mémoire. Avant d'exécuter une requête avec un agrégat de hachage, SQL Server utilise des estimations de cardinalité pour estimer la quantité de mémoire dont nous avons besoin pour exécuter la requête. Avec une jointure de hachage, nous stockons chaque ligne de génération, de sorte que la mémoire totale requise est proportionnelle au nombre et à la taille des lignes de génération. Le nombre de lignes qui se joignent et la cardinalité de sortie de la jointure n'ont aucun effet sur les besoins en mémoire de la jointure. Avec un agrégat de hachage, nous stockons une ligne pour chaque groupe, de sorte que la mémoire totale requise est en fait proportionnelle au nombre et à la taille des groupes ou des lignes de sortie. Si nous avons moins de valeurs uniques du groupe par colonne (s) et moins de groupes, nous avons besoin de moins de mémoire. Si nous avons des valeurs plus uniques du groupe par colonne (s) et plus de groupes, nous avons besoin de plus de mémoire.

Il continue en parlant de la récursivité du hachage:

Alors, que se passe-t-il si nous manquons de mémoire? Encore une fois, comme la jointure par hachage, si nous manquons de mémoire, nous devons commencer à répandre des lignes dans tempdb. Nous renversons un ou plusieurs compartiments ou partitions, y compris les résultats partiellement agrégés, ainsi que toutes les nouvelles lignes supplémentaires qui hachent les compartiments ou partitions renversés. Bien que nous n'essayions pas d'agréger les nouvelles lignes renversées, nous les hachons et les divisons en plusieurs compartiments ou partitions. Une fois que nous avons fini de traiter tous les groupes d'entrée, nous sortons les groupes en mémoire terminés et répétons l'algorithme en relisant et en agrégeant une partition renversée à la fois. En divisant les lignes déversées en plusieurs partitions, nous réduisons la taille de chaque partition et, ainsi, le risque que l'algorithme doive se répéter plusieurs fois.

Renflouement

Le sauvetage de hachage est légèrement documenté, mais mentionné par Nacho Alonso Portillo dans Quel est le niveau maximal de récursivité pour l'itérateur de hachage avant de forcer le renflouement?

La valeur est une constante, codée en dur dans le produit, et sa valeur est cinq (5). Cela signifie qu'avant que l'opérateur de hachage ait recours à un algorithme basé sur le tri pour une sous-partition donnée qui ne rentre pas dans la mémoire accordée à partir de l'espace de travail, cinq tentatives précédentes de subdiviser la partition d'origine en partitions plus petites doivent avoir eu lieu.

L '"opérateur de balayage de hachage" mentionné il y a une référence à la classe interne CQScanHashdans sqlmin.dll. Cette classe dirige l'implémentation de l'opérateur de hachage (sous toutes ses formes, y compris les agrégats partiels et les flux distincts) que nous voyons dans les plans d'exécution.

Algorithme de renflouement

Cela nous amène au cœur de vos questions - que fait exactement l'algorithme de sauvetage? Est-ce «basé sur le tri» ou basé sur «une sorte de boucle imbriquée»?

Il s'agit sans doute des deux, selon votre point de vue. Lorsque la récursion de hachage atteint le niveau 5, la partition de hachage en mémoire passe d'une table de hachage à un index b-tree initialement vide sur les valeurs de hachage. Chaque ligne d'une seule partition de hachage précédemment déversée est recherchée dans l'index b-tree et insérée (nouveau groupe) ou mise à jour (en conservant les agrégats) selon le cas.

Cette série d'insertions non ordonnées dans un arbre b peut également être considérée comme un tri par insertion ou comme une recherche de boucles imbriquées indexées.

Dans tous les cas, cet algorithme de secours est garanti de se terminer éventuellement sans allouer plus de mémoire. Il peut nécessiter plusieurs passes si l'espace disponible pour l'arborescence b n'est pas suffisant pour contenir toutes les clés de regroupement et les agrégats de la partition de débordement.

Une fois que la mémoire disponible pour contenir l'index b-tree est épuisée, toutes les lignes supplémentaires (de la partition déversée actuelle) sont envoyées à une seule nouvelle partition tempdb (qui est garantie d'être plus petite) et le processus se répète si nécessaire. Le niveau de déversement reste à 5 car la récursivité du hachage est terminée. Certains détails de traitement peuvent être observés avec l'indicateur de trace non documenté 7357.

Paul White 9
la source