Rescate de agregado de hash

Respuestas:

11

La combinación hash y el agregado hash usan internamente el mismo código de operador, aunque un agregado hash usa solo una entrada (compilación). El funcionamiento básico del agregado de hash se describe por Craig Freedman :

Al igual que con la combinación hash, el agregado hash requiere memoria. Antes de ejecutar una consulta con un agregado hash, SQL Server usa estimaciones de cardinalidad para estimar cuánta memoria necesitamos para ejecutar la consulta. Con una combinación hash, almacenamos cada fila de compilación, por lo que el requisito de memoria total es proporcional al número y tamaño de las filas de compilación. El número de filas que se unen y la cardinalidad de salida de la unión no tienen ningún efecto sobre el requisito de memoria de la unión. Con un agregado hash, almacenamos una fila para cada grupo, por lo que el requisito de memoria total es en realidad proporcional al número y tamaño de los grupos o filas de salida. Si tenemos menos valores únicos del grupo por columna (s) y menos grupos, necesitamos menos memoria. Si tenemos más valores únicos del grupo por columna (s) y más grupos, necesitamos más memoria.

Continúa hablando sobre la recurrencia del hash:

Entonces, ¿qué pasa si se nos acaba la memoria? Nuevamente, como hash join, si nos quedamos sin memoria, debemos comenzar a derramar filas a tempdb. Derramamos uno o más cubos o particiones, incluidos los resultados agregados parcialmente, junto con las filas nuevas adicionales que se combinan con los cubos o particiones derramados. Aunque no intentamos agregar las nuevas filas derramadas, las hacemos en hash y las dividimos en varios cubos o particiones. Una vez que hemos terminado de procesar todos los grupos de entrada, sacamos los grupos en memoria completos y repetimos el algoritmo leyendo de nuevo y agregando una partición derramada a la vez. Al dividir las filas derramadas en múltiples particiones, reducimos el tamaño de cada partición y, por lo tanto, reducimos el riesgo de que el algoritmo deba repetirse muchas veces.

Rescate

El rescate de hash está ligeramente documentado, pero Nacho Alonso Portillo lo menciona en ¿Cuál es el nivel máximo de recursión para el iterador de hash antes de forzar el rescate?

El valor es un constante, codificado en el producto, y su valor es cinco (5). Esto significa que antes de que el operador de escaneo hash recurra a un algoritmo basado en clasificación para cualquier subpartición dada que no se ajuste a la memoria otorgada desde el espacio de trabajo, deben haber ocurrido cinco intentos previos para subdividir la partición original en particiones más pequeñas.

El "operador de escaneo hash" mencionó que hay una referencia a la clase interna CQScanHashen sqlmin.dll. Esta clase encabeza la implementación del operador hash (en todas sus formas, incluidos los agregados parciales y el flujo distinto) que vemos en los planes de ejecución.

Algoritmo de rescate

Esto nos lleva al centro de sus preguntas: ¿qué hace exactamente el algoritmo de rescate? ¿Está "basado en una clasificación" o basado en "una especie de cosa de bucles anidados"?

Podría decirse que es ambos, dependiendo de su punto de vista. Cuando la recursividad hash alcanza el nivel 5, la partición hash en memoria cambia de ser una tabla hash a un índice b-tree inicialmente vacío en los valores hash. Cada fila de una única partición hash previamente derramada se busca en el índice b-tree y se inserta (nuevo grupo) o se actualiza (manteniendo agregados) según corresponda.

Esta serie de inserciones no ordenadas en un árbol b puede verse igualmente como un tipo de inserción o como una búsqueda de bucles anidados indexados.

En cualquier caso, se garantiza que este algoritmo alternativo se completará eventualmente sin asignar más memoria. Puede requerir múltiples pases si el espacio disponible para el b-tree no es suficiente para contener todas las claves de agrupación y agregados de la partición de desbordamiento.

Una vez que la memoria disponible para contener el índice b-tree se agota, las filas adicionales (de la partición actual derramada) se envían a una nueva partición tempdb nueva (que se garantiza que será más pequeña) y el proceso se repite según sea necesario. El nivel de derrame permanece en 5 porque la recursividad de hash ha finalizado. Algunos detalles de procesamiento se pueden observar con el indicador de traza no documentado 7357.

Paul White 9
fuente