Parte de su consulta inicial es la siguiente.
FROM [dbo].[calendar] a
LEFT JOIN [dbo].[colleagueList] b
ON b.[Date] = a.d
WHERE DAY(a.[d]) = 1
AND a.[d] BETWEEN @dateStart AND COALESCE(@dateEnd,@dateStart)
Esa sección del plan se muestra a continuación
Su consulta revisada BETWEEN @dateStart AND ISNULL(@dateEnd,@dateStart)
tiene esto para la misma combinación
La diferencia parece ser que se ISNULL
simplifica aún más y, como resultado, obtienes estadísticas de cardinalidad más precisas en la próxima unión. Esta es una función con valores de tabla en línea y la está llamando con valores literales para que pueda hacer algo así.
a.[d] BETWEEN @dateStart AND ISNULL(@dateEnd,@dateStart)
a.[d] BETWEEN '2013-06-01' AND ISNULL(NULL,'2013-06-01')
a.[d] BETWEEN '2013-06-01' AND '2013-06-01'
a.[d] = '2013-06-01'
Y como hay un predicado de equi join, b.[Date] = a.d
el plan también muestra un predicado de igualdad b.[Date] = '2013-06-01'
. Como resultado, 28,393
es probable que la estimación de cardinalidad de las filas sea bastante precisa.
Para la versión CASE
/ COALESCE
cuando @dateStart
y @dateEnd
son el mismo valor, entonces simplifica OK a la misma expresión de igualdad y proporciona el mismo plan, pero cuando @dateStart = '2013-06-01'
y @dateEnd IS NULL
solo va tan lejos como
a.[d]>='2013-06-01' AND a.[Date]<=CASE WHEN (1) THEN '2013-06-01' ELSE NULL END
que también se aplica como un predicado implícito en ColleagueList
. El número estimado de filas esta vez es 79.8
filas.
La próxima unión es
LEFT JOIN colleagueTime
ON colleagueTime.TC_DATE = colleagueList.Date
AND colleagueTime.ASSOC_ID = CAST(colleagueList.ID AS VARCHAR(10))
colleagueTime
es una 3,249,590
tabla de filas que (de nuevo) aparentemente es un montón sin índices útiles.
Esta discrepancia en las estimaciones afecta la elección de combinación utilizada. El ISNULL
plan elige una combinación hash que solo escanea la tabla una vez. El COALESCE
plan elige una unión de bucles anidados y estima que solo tendrá que escanear la tabla una vez y poder poner en cola el resultado y reproducirlo 78 veces. es decir, estima que los parámetros correlacionados no cambiarán.
Por el hecho de que el plan de bucles anidados seguía funcionando después de dos horas, esta suposición de un solo escaneo en contra colleagueTime
parece ser muy inexacta.
En cuanto a por qué el número estimado de filas entre las dos uniones es mucho menor, no estoy seguro sin poder ver las estadísticas en las tablas. La única forma en que logré sesgar los recuentos de filas estimados tanto en mis pruebas fue agregando una carga de NULL
filas (esto redujo el recuento de filas estimado a pesar de que el número real de filas devueltas permaneció igual).
El recuento de filas estimado en el COALESCE
plan con mis datos de prueba fue del orden de
number of rows matching >= condition * 30% * (proportion of rows in the table not null)
O en SQL
SELECT 1E0 * COUNT([Date]) / COUNT(*) * ( COUNT(CASE
WHEN [Date] >= '2013-06-01' THEN 1
END) * 0.30 )
FROM [dbo].[colleagueList]
pero esto no cuadra con su comentario de que la columna no tiene NULL
valores.