¿Por qué la subconsulta usa paralelismo y la unión no?

16

¿Por qué el servidor SQL usa el paralelismo cuando ejecuta esta consulta que usa una subconsulta pero no cuando usa una unión? La versión de unión se ejecuta en serie y tarda aproximadamente 30 veces más en completarse.

Únete a la versión: ~ 30 segundos

ingrese la descripción de la imagen aquí

Versión de subconsulta: <1 segundo

ingrese la descripción de la imagen aquí

EDITAR: versiones Xml del plan de consulta:

ÚNETE a la versión

Versión de SUBQUERY

Chris L
fuente

Respuestas:

12

Como ya se indicó en los comentarios, parece que necesita actualizar sus estadísticas.

El número estimado de filas que salen de la unión entre locationy testrunses muy diferente entre los dos planes.

Unirse a las estimaciones del plan: 1

Plan 1

Estimaciones del plan de subconsulta: 8.748

ingrese la descripción de la imagen aquí

El número real de filas que salen de la unión es 14,276.

Por supuesto, no tiene ningún sentido intuitivo que la versión de unión deba estimar que 3 filas deberían provenir locationy producir una sola fila unida, mientras que la subconsulta estima que una sola de esas filas producirá 8.748 de la misma unión, pero de todos modos pude para reproducir esto

Esto parece suceder si no hay cruce entre los histogramas cuando se crean las estadísticas. La versión de unión supone una sola fila. Y la búsqueda de igualdad única de la subconsulta supone las mismas filas estimadas que una búsqueda de igualdad contra una variable desconocida.

La cardinalidad de testruns es 26244. Suponiendo que se rellena con tres identificadores de ubicación distintos, la siguiente consulta estima que 8,748se devolverán las filas ( 26244/3)

declare @i int

SELECT *
FROM   testruns AS tr
WHERE  tr.location_id = @i

Dado que la tabla locationssolo contiene 3 filas, es fácil (si suponemos que no hay claves externas) idear una situación en la que se crean las estadísticas y luego los datos se modifican de una manera que afecta drásticamente el número real de filas devueltas pero es insuficiente para desconecte la actualización automática de estadísticas y vuelva a compilar el umbral.

A medida que SQL Server obtiene el número de filas que salen de esa unión tan mal, todas las otras estimaciones de filas en el plan de unión se subestiman enormemente. Además de significar que obtiene un plan en serie, la consulta también obtiene una concesión de memoria insuficiente y las clasificaciones y las combinaciones hash se derraman tempdb.

A continuación se muestra un posible escenario que reproduce las filas reales frente a las estimadas que se muestran en su plan.

CREATE TABLE location
  (
     id       INT CONSTRAINT locationpk PRIMARY KEY,
     location VARCHAR(MAX) /*From the separate filter think you are using max?*/
  )

/*Temporary ids these will be updated later*/
INSERT INTO location
VALUES      (101, 'Coventry'),
            (102, 'Nottingham'),
            (103, 'Derby')

CREATE TABLE testruns
  (
     location_id INT
  )

CREATE CLUSTERED INDEX IX ON testruns(location_id)

/*Add in 26244 rows of data split over three ids*/
INSERT INTO testruns
SELECT TOP (5984) 1
FROM   master..spt_values v1, master..spt_values v2
UNION ALL
SELECT TOP (5984) 2
FROM   master..spt_values v1, master..spt_values v2
UNION ALL
SELECT TOP (14276) 3
FROM   master..spt_values v1, master..spt_values v2

/*Create statistics. The location_id histograms don't intersect at all*/
UPDATE STATISTICS location(locationpk) WITH FULLSCAN;    
UPDATE STATISTICS testruns(IX) WITH FULLSCAN;

/* UPDATE location.id. Three row update is below recompile threshold*/
UPDATE location
SET    id = id - 100

Luego, ejecutar las siguientes consultas da la misma discrepancia estimada vs real

SELECT *
FROM   testruns AS tr
WHERE  tr.location_id = (SELECT id
                         FROM   location
                         WHERE  location = 'Derby')

SELECT *
FROM   testruns AS tr
       JOIN location loc
         ON tr.location_id = loc.id
WHERE  loc.location = ( 'Derby' ) 
Martin Smith
fuente
Si se agrega una restricción única en la ubicación, resulta obvio que "=" devolverá exactamente una fila. Luego, en su ejemplo, los planes de consulta se vuelven idénticos (escaneos -> búsquedas): alterar la ubicación de la tabla agregar restricción U_Location_Location único no agrupado (Ubicación);
crokusek
@crokusek sí. ¡Me di cuenta de lo que querías decir después y borré mi comentario! ¿Eso aumenta el número estimado de filas para que la versión de unión sea igual que la subconsulta también? ¿No está en la PC en este momento para probar?
Martin Smith
@crokusek Sí. parece las mismas filas estimadas fuera de la unión que para la subconsulta en ese caso singleton.
Martin Smith
Si. Plan de consulta idéntico, ambos estiman 8748, ambos datos reales 14276. Por cierto, pensé que calcular previamente el locationId resolvería esa diferencia, pero no lo hace.
crokusek
1
@crokusek: también agregaré la restricción única a la ubicación y otros lugares similares dentro de mi base de datos. Debo admitir que no me di cuenta que afectó la optimización de consultas. Pensé que era solo para garantizar la integridad de los datos. Gracias por su aporte en esta pregunta.
Chris L