sql >> Base de Datos >  >> RDS >> Database

Cómo se inician los planes paralelos - Parte 1

Esta serie de cinco partes profundiza en la forma en que se inician los planes paralelos en modo fila de SQL Server. Esta primera parte cubre el papel de la tarea principal (coordinador) en la preparación del plan para la ejecución paralela. Incluye la inicialización de cada operador y la adición de perfiladores ocultos para recopilar datos de rendimiento en tiempo de ejecución, como el recuento real de filas y el tiempo transcurrido.

Configuración

Para proporcionar una base concreta para el análisis, seguiremos cómo comienza la ejecución de una consulta paralela en particular. Usé el Stack Overflow 2013 público base de datos (descargar detalles). La forma deseada del plan también se puede obtener contra el conjunto de datos más pequeño de Stack Overflow 2010 si eso es más conveniente. Se puede descargar en el mismo enlace. Agregué un índice no agrupado:

CREATE NONCLUSTERED INDEX PP
ON dbo.Posts
(
    PostTypeId ASC,
    CreationDate ASC
);

Mi entorno de prueba es SQL Server 2019 CU9 en una laptop con 8 cores y 16GB de memoria asignada a la instancia. Nivel de compatibilidad 150 se usa exclusivamente. Menciono esos detalles para ayudarlo a reproducir el plan objetivo si lo desea. Los fundamentos de la ejecución paralela en modo de fila no han cambiado desde SQL Server 2005, por lo que la siguiente discusión es ampliamente aplicable.

La consulta de prueba devuelve el número total de preguntas y respuestas, agrupadas por mes y año:

WITH 
    MonthlyPosts AS 
    (
        SELECT 
            P.PostTypeId, 
            CA.TheYear, 
            CA.TheMonth, 
            Latest = MAX(P.CreationDate)
        FROM dbo.Posts AS P
        CROSS APPLY 
        (
            VALUES
            (
                YEAR(P.CreationDate), 
                MONTH(P.CreationDate)
            )
        ) AS CA (TheYear, TheMonth)
        GROUP BY 
            P.PostTypeId, 
            CA.TheYear, 
            CA.TheMonth
    )
SELECT 
    rn = ROW_NUMBER() OVER (
        ORDER BY Q.TheYear, Q.TheMonth),
    Q.TheYear, 
    Q.TheMonth, 
    LatestQuestion = Q.Latest,
    LatestAnswer = A.Latest
FROM MonthlyPosts AS Q
JOIN MonthlyPosts AS A
    ON A.TheYear = Q.TheYear
    AND A.TheMonth = Q.TheMonth
WHERE 
    Q.PostTypeId = 1
    AND A.PostTypeId = 2
ORDER BY 
    Q.TheYear,
    Q.TheMonth
OPTION 
(
    USE HINT ('DISALLOW_BATCH_MODE'),
    USE HINT ('FORCE_DEFAULT_CARDINALITY_ESTIMATION'),
    ORDER GROUP,
    MAXDOP 2
);

He usado sugerencias para obtener un plan de modo de fila de forma particular. La ejecución se limita a DOP 2 para que algunos de los detalles que se muestran más adelante sean más concisos.

El plan de ejecución estimado es (haga clic para ampliar):

Fondo

El optimizador de consultas produce un solo plan compilado para un lote. Cada declaración en el lote está marcada para ejecución en serie o en paralelo, según la elegibilidad y los costos estimados.

Un plan paralelo contiene intercambios (operadores de paralelismo). Los intercambios pueden aparecer en flujos distribuidos , flujos de partición , o reunir flujos forma. Cada uno de estos tipos de intercambio utiliza los mismos componentes subyacentes, solo que están conectados de manera diferente, con una cantidad diferente de entradas y salidas. Para obtener más información sobre la ejecución en paralelo en modo fila, consulte Planes de ejecución en paralelo:ramas y subprocesos.

Rebaja de DOP

El grado de paralelismo (DOP) para un plan paralelo puede reducirse en tiempo de ejecución si es necesario. Una consulta paralela podría comenzar solicitando DOP 8, pero degradarse progresivamente a DOP 4, DOP 2 y finalmente DOP 1 debido a la falta de recursos del sistema en ese momento. Si desea verlo en acción, vea este breve video de Erik Darling.

La ejecución de un plan paralelo en un solo subproceso también puede ocurrir cuando una sesión que está limitada a DOP 1 por una configuración ambiental (por ejemplo, máscara de afinidad o regulador de recursos) reutiliza un plan paralelo almacenado en caché. Consulte Mito:SQL Server almacena en caché un plan en serie con cada plan paralelo para obtener más detalles.

Sea cual sea la causa, la degradación de DOP de un plan paralelo almacenado en caché no resultar en la compilación de un nuevo plan serial. SQL Server reutiliza el plan paralelo existente al deshabilitar los intercambios El resultado es un plan 'paralelo' que se ejecuta en un solo hilo. Los intercambios siguen apareciendo en el plan, pero se omiten en tiempo de ejecución.

SQL Server no puede promover un plan en serie para la ejecución en paralelo agregando intercambios en tiempo de ejecución. Eso requeriría una nueva compilación.

Inicialización del plan paralelo

Un plan paralelo tiene todos los intercambios necesarios para utilizar subprocesos de trabajo adicionales, pero hay trabajo de configuración adicional necesario en tiempo de ejecución antes de que pueda comenzar la ejecución en paralelo. Un ejemplo obvio es que se deben asignar subprocesos de trabajo adicionales a tareas específicas dentro del plan, pero hay mucho más que eso.

Comenzaré en el punto en el que se recuperó un plan paralelo de la memoria caché del plan. En este punto, solo existe el subproceso original que procesa la solicitud actual. Este subproceso a veces se denomina "subproceso coordinador" en planes paralelos, pero prefiero los términos "tarea principal ” o “padre trabajador”. Por lo demás, no hay nada especial en este hilo; es el mismo subproceso que utiliza la conexión para procesar las solicitudes de los clientes y ejecutar los planes en serie hasta su finalización.

Para enfatizar el punto de que solo existe un único hilo ahora mismo, quiero que visualices el plan en este momento así:

Usaré capturas de pantalla de Sentry One Plan Explorer casi exclusivamente en esta publicación, pero solo para esta primera vista, también mostraré la versión SSMS:

En cualquier representación, la diferencia clave es la falta de iconos de paralelismo en cada operador, aunque los intercambios todavía están presentes. Solo la tarea principal existe en este momento, ejecutándose en el subproceso de conexión original. Sin subprocesos de trabajo adicionales ya se han reservado, creado o asignado tareas. Tenga presente la representación del plan anterior a medida que avanzamos.

Creando el plan ejecutable

El plan en este punto es esencialmente solo una plantilla que se puede utilizar como base para cualquier ejecución futura. Para prepararlo para una ejecución específica, SQL Server debe completar los valores de tiempo de ejecución como el usuario actual, el contexto de la transacción, los valores de los parámetros, los identificadores de cualquier objeto creado en el tiempo de ejecución (por ejemplo, tablas y variables temporales), etc.

Para un plan paralelo, SQL Server necesita hacer bastante trabajo preparatorio adicional para que la maquinaria interna llegue al punto en que pueda comenzar la ejecución. El subproceso de trabajo de la tarea principal es responsable de realizar casi todo este trabajo (y ciertamente todo el trabajo que cubriremos en la parte 1).

El proceso de transformación de la plantilla del plan para una ejecución específica se conoce como creación del plan ejecutable. . A veces es difícil mantener la terminología correcta, porque los términos a menudo están sobrecargados y mal aplicados (incluso por Microsoft), pero haré todo lo posible para ser lo más coherente posible.

Contextos de ejecución

Puedes pensar en un contexto de ejecución como una plantilla de plan rellenada con toda la información de tiempo de ejecución específica que necesita un subproceso en particular. El plan ejecutable para una serie consta de un solo contexto de ejecución, donde un solo subproceso ejecuta todo el plan.

Un paralelo plan ejecutable contiene una colección de contextos de ejecución :uno para la tarea principal y uno por subproceso en cada rama paralela. Cada subproceso de trabajo paralelo adicional ejecuta su parte del plan general dentro de su propio contexto de ejecución. Por ejemplo, un plan paralelo con tres ramas que se ejecutan en DOP 8 tiene (1 + (3 * 8)) =25 contextos de ejecución. Los contextos de ejecución en serie se almacenan en caché para su reutilización, pero los contextos de ejecución en paralelo adicionales no.

La tarea principal siempre existe antes que cualquier tarea paralela adicional, por lo que se le asigna contexto de ejecución cero . Los contextos de ejecución utilizados por los trabajadores paralelos se crearán más adelante, una vez que el contexto principal se haya inicializado por completo. Los contextos adicionales están clonados desde el contexto principal, luego personalizado para su tarea específica (esto se trata en la parte 2).

Hay una serie de actividades involucradas en el inicio del contexto de ejecución cero. No es práctico intentar enumerarlos todos, pero será útil cubrir algunos de los principales aplicables a nuestra consulta de prueba. Todavía habrá demasiados para una sola lista, así que los dividiré en secciones (algo arbitrarias):

1. Inicialización del contexto principal

Cuando enviamos la instrucción para su ejecución, el contexto de la tarea principal (contexto de ejecución cero) se inicializa con:

  • Una referencia a la transacción base (explícito, implícito o de confirmación automática). Los trabajadores paralelos ejecutarán subtransacciones, pero todas están dentro del alcance de la transacción base.
  • Una lista de parámetros de declaración y sus valores actuales.
  • Un objeto de memoria principal (PMO) utilizado para administrar asignaciones y concesiones de memoria.
  • Un mapa vinculado de los operadores (nodos de consulta) en el plan ejecutable.
  • Una fábrica para cualquier objeto grande requerido (manchas) manijas.
  • Clases de bloqueo para realizar un seguimiento de varios bloqueos retenidos durante un período durante la ejecución. No todos los planes requieren clases de bloqueo ya que los operadores de transmisión completa suelen bloquear y desbloquear filas individuales en secuencia.
  • La concesión de memoria estimada para la consulta.
  • Concesión de memoria en modo fila comentarios estructuras para cada operador (SQL Server 2019).

Muchas de estas cosas serán utilizadas o referenciadas por tareas paralelas más adelante, por lo que primero deben existir en el ámbito principal.

2. Metadatos de contexto principal

Las siguientes tareas principales realizadas son:

  • Comprobación del coste de consulta estimado está dentro del límite establecido por las opciones de configuración del límite de costo del regulador de consulta.
  • Actualización del uso del índice registros:expuestos a través de sys.dm_db_index_usage_stats .
  • Creación de valores de expresión en caché (constantes de tiempo de ejecución).
  • Crear una lista de operadores de perfiles se utiliza para recopilar métricas de tiempo de ejecución, como recuentos de filas y tiempos, si se ha solicitado para la ejecución actual. Los generadores de perfiles en sí aún no se han creado, solo la lista.
  • Tomar una instantánea de esperas para la función de espera de sesión expuesta a través de sys.dm_exec_session_wait_stats .

3. DOP y concesión de memoria

El contexto de la tarea principal ahora:

  • Calcula el grado de paralelismo en tiempo de ejecución (DOP ). Esto se ve afectado por la cantidad de trabajadores libres (consulte "Degradación de DOP" anteriormente), dónde se pueden colocar entre los nodos y una cantidad de marcas de rastreo.
  • Reserva el número necesario de subprocesos. Este paso es contabilidad pura:es posible que los subprocesos en sí mismos no existan en este punto. SQL Server realiza un seguimiento de la cantidad máxima de subprocesos que puede tener. Reservar hilos resta de ese número. Cuando se acaban los hilos, el número máximo se incrementa de nuevo.
  • Establece tiempo de espera de concesión de memoria .
  • Calcula la concesión de memoria, incluida la memoria necesaria para los búferes de intercambio.
  • Adquiere la concesión de memoria a través del semáforo de recursos adecuado .
  • Crea un objeto administrador para manejar subprocesos paralelos . La tarea principal es el proceso de nivel superior; las tareas adicionales también se conocen como subprocesos .

Si bien los subprocesos están "reservados" en este punto, SQL Server aún puede encontrar THREADPOOL espera más tarde cuando intenta usar uno de los subprocesos 'reservados'. La reserva garantiza que SQL Server permanecerá alrededor de su número máximo configurado de subprocesos en todo momento, pero es posible que el subproceso físico no esté disponible de inmediato desde el grupo de subprocesos . Cuando eso suceda, el sistema operativo deberá iniciar un nuevo subproceso, lo que puede demorar un poco. Para obtener más información al respecto, consulte Unusual THREADPOOL Waits de Josh Darnell.

4. Configuración de análisis de consultas

Los planes en modo fila se ejecutan en iterativo moda, empezando por la raíz. El plan que tenemos en este momento aún no es capaz de este modo de ejecución. Todavía es en gran parte una plantilla, incluso si ya contiene una buena cantidad de información específica de ejecución.

SQL Server necesita convertir la estructura actual en un árbol de iteradores , cada uno con métodos como Open , GetRow y Close . Los métodos del iterador están conectados a sus hijos a través de punteros de función. Por ejemplo, llamar a GetRow en la raíz llama recursivamente a GetRow en operadores secundarios hasta que se alcanza un nivel de hoja y una fila comienza a "burbujear" en el árbol. Para refrescar los detalles, consulte Iteradores, planes de consulta y por qué se ejecutan al revés.

Fin de la Parte 1

Hemos hecho un buen progreso configurando el contexto de ejecución para la tarea principal. En la parte 2, seguiremos mientras SQL Server construye el árbol de exploración de consultas necesario para la ejecución iterativa.