¿Por qué el operador de paralelismo (flujos de partición) reduce las estimaciones de filas a 1?

12

Estoy usando SQL Server 2012 Enterprise. Me he encontrado con un plan SQL que exhibe un comportamiento que no encuentro completamente intuitivo. Después de una operación pesada de Escaneo de Índice Paralelo, ocurre una operación de Paralelismo (Secuencias de Repartición), pero está matando las estimaciones de fila devueltas por el Escaneo de Índice (Object10.Index2), reduciendo la estimación a 1. He hecho algunas búsquedas, pero No he encontrado nada que explique este comportamiento. La consulta es bastante simple, aunque cada una de las tablas contiene registros de pocos millones. Esto es parte de un proceso de carga DWH y este conjunto de datos intermedios se toca varias veces, pero la pregunta que tengo está relacionada con las estimaciones de fila en particular. ¿Alguien puede explicar por qué las estimaciones precisas de filas van a 1 dentro del Operador Paralelismo (Strems de Repartición)? También,

He publicado el plan completo para pegar el plan .

Aquí está la operación en cuestión:

ingrese la descripción de la imagen aquí

Incluyendo el Árbol de planes en caso de que agregue más contexto:

ingrese la descripción de la imagen aquí

¿Podría encontrarme con alguna variación de este elemento de Connect presentado por Paul White (una explicación más detallada en su blog aquí )? Al menos es lo único que he encontrado que parece estar remotamente cerca de lo que me encuentro, a pesar de que no hay un operador TOP en juego.

John Eisbrener
fuente

Respuestas:

9

Los planes de consulta con filtros de mapa de bits a veces pueden ser difíciles de leer. Del artículo de BOL para las secuencias de reparto (énfasis mío):

El operador Repartition Streams consume múltiples flujos y produce múltiples flujos de registros. El contenido y el formato del registro no se modifican. Si el optimizador de consultas utiliza un filtro de mapa de bits, se reduce el número de filas en la secuencia de salida.

Además, un artículo sobre filtros de mapa de bits también es útil:

Al analizar un plan de ejecución que contiene un filtro de mapa de bits, es importante comprender cómo fluyen los datos a través del plan y dónde se aplica el filtrado. El filtro de mapa de bits y el mapa de bits optimizado se crean en el lado de entrada de compilación (la tabla de dimensiones) de una unión hash; sin embargo, el filtrado real generalmente se realiza dentro del operador de paralelismo, que está en el lado de entrada de la sonda (la tabla de hechos) de la unión hash. Sin embargo, cuando el filtro de mapa de bits se basa en una columna de enteros, el filtro se puede aplicar directamente a la operación de exploración de índice o tabla inicial en lugar del operador de paralelismo. Esta técnica se llama optimización en fila.

Creo que eso es lo que estás observando con tu consulta. Es posible crear una demostración relativamente simple para mostrar un operador de flujos de reparto que reduce una estimación de cardinalidad, incluso cuando el operador de mapa de bits está en IN_ROWcontra de la tabla de hechos. Preparación de datos:

create table outer_tbl (ID BIGINT NOT NULL);

INSERT INTO outer_tbl WITH (TABLOCK)
SELECT TOP (1000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values;

create table inner_tbl_1 (ID BIGINT NULL);
create table inner_tbl_2 (ID BIGINT NULL);

INSERT INTO inner_tbl_1 WITH (TABLOCK)
SELECT (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) / 2000000 - 2) NUM
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;

INSERT INTO inner_tbl_2 WITH (TABLOCK)
SELECT (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) / 2000000 - 2) NUM
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;

Aquí hay una consulta que no debe ejecutar:

SELECT *
FROM outer_tbl o
INNER JOIN inner_tbl_1 i ON o.ID = i.ID
INNER JOIN inner_tbl_2 i2 ON o.ID = i2.ID
OPTION (HASH JOIN, QUERYTRACEON 9481, QUERYTRACEON 8649);

Subí el plan . Eche un vistazo al operador cerca de inner_tbl_2:

repartición de filas perdedoras

También puede encontrar útil la segunda prueba en Hash Joins on Nullable Columns por Paul White.

Hay algunas inconsistencias en cómo se aplica la reducción de filas. Solo pude verlo en un plan con al menos tres tablas. Sin embargo, la reducción en las filas esperadas parece razonable con la distribución de datos correcta. Suponga que la columna unida en la tabla de hechos tiene muchos valores repetidos que no están presentes en la tabla de dimensiones. Un filtro de mapa de bits podría eliminar esas filas antes de que lleguen a la unión. Para su consulta, la estimación se reduce a 1. La forma en que las filas se distribuyen entre la función hash proporciona una buena pista:

distribución de fila

En base a eso, sospecho que tiene muchos valores repetidos para la Object1.Column21columna. Si las columnas repetidas no están en el histograma de estadísticas, Object4.Column19entonces SQL Server podría obtener la estimación de cardinalidad muy incorrecta.

Creo que debería preocuparse porque podría ser posible mejorar el rendimiento de la consulta. Por supuesto, si la consulta cumple con el tiempo de respuesta o los requisitos de SLA, entonces puede que no valga la pena investigar más. Sin embargo, si desea investigar más a fondo, hay algunas cosas que puede hacer (además de actualizar las estadísticas) para tener una idea de si el optimizador de consultas elegiría un mejor plan si tuviera mejor información. Puede colocar los resultados de la unión entre Database1.Schema1.Object10y Database1.Schema1.Object11en una tabla temporal y ver si continúa obteniendo uniones de bucle anidadas. Puede cambiar esa unión a una LEFT OUTER JOINpara que el optimizador de consultas no reduzca el número de filas en ese paso. Puede agregar una MAXDOP 1pista a su consulta para ver qué sucede. Podrías usarTOPjunto con una tabla derivada para forzar que la unión vaya al último, o incluso podría comentar la unión desde la consulta. Esperemos que estas sugerencias sean suficientes para comenzar.

Con respecto al elemento de conexión en la pregunta, es extremadamente improbable que esté relacionado con su pregunta. Ese problema no tiene que ver con estimaciones de filas pobres. Tiene que ver con una condición de carrera en paralelo que hace que se procesen demasiadas filas en el plan de consulta detrás de escena. Aquí parece que su consulta no está haciendo ningún trabajo adicional.

Joe Obbish
fuente
6

El problema central aquí es una estimación de cardinalidad pobre para el resultado de la primera unión. Esto puede surgir por muchas razones, pero lo más frecuente es que sean estadísticas desactualizadas o varios predicados de unión correlacionados, que el modelo predeterminado del optimizador supone que son independientes.

En el último caso, REVISIÓN: bajo rendimiento cuando ejecuta una consulta que contiene predicados Y correlacionados en SQL Server 2008 o en SQL Server 2008 R2 o en SQL Server 2012 puede ser relevante utilizando el indicador de seguimiento compatible 4137. También puede intentar la consulta con trace flag 4199 para habilitar las correcciones del optimizador, y / o 2301 para habilitar las extensiones de modelado. Es difícil saberlo sobre la base de un plan anónimo.

La presencia del mapa de bits no afecta directamente la estimación de cardinalidad de la unión, pero sí hace que su efecto sea visible antes aplicando una reducción de semiunión temprana. Sin el mapa de bits, la estimación de cardinalidad para la primera unión sería la misma, y ​​el resto del plan aún se optimizaría en consecuencia.

Si tiene curiosidad, en un sistema de prueba, puede deshabilitar mapas de bits para la consulta con la marca de seguimiento 7498. También puede deshabilitar mapas de bits optimizados (considerados por el optimizador y que afectan las estimaciones de cardinalidad), reemplazándolos por mapas de bits posteriores a la optimización (no considerados por el optimizador, no tiene efecto en la cardinalidad) con una combinación de marcas de rastreo 7497 y 7498. Ninguno de los dos está documentado o respaldado para su uso en un sistema de producción, pero producen planes que el optimizador podría considerar normalmente, y por lo tanto pueden ser forzados con un guía de plan

Nada de esto resolverá el problema central de la mala estimación para la primera unión como se señaló anteriormente, por lo que realmente solo lo menciono por el bien de los intereses.

Lecturas adicionales en mapas de bits y combinaciones de hash:

Paul White 9
fuente
0

te respondí en Twitter. Miré el XML adjunto y vi un paralelismo desequilibrado. 1 hilo tiene casi todas las filas reales, mientras que la mayoría de los otros no. Eso grita paralelismo desequilibrado está ocurriendo. Por lo tanto, examinaría la clave / valor de unión y sus estadísticas y cardinalidad respectivas.

Según su otra idea, no estoy tan seguro de que se aplique el elemento Connect, ya que su plan pegado no contiene TOP en ningún lugar que vi.

SQLBek
fuente