Creé una función que acepta una fecha de inicio y finalización, siendo la fecha de finalización opcional. Luego escribí un CASE
en el filtro para usar la fecha de inicio si no se pasa ninguna fecha de finalización.
CASE WHEN @dateEnd IS NULL
THEN @dateStart
ELSE @dateEnd
END
Cuando llamo a la función para el mes más reciente de los datos:
SELECT * FROM theFunction ('2013-06-01', NULL)
... la consulta se cuelga. Si especifico la fecha de finalización:
SELECT * FROM theFunction ('2013-06-01', '2013-06-01')
... el resultado se devuelve normalmente. Saqué el código de la función y lo ejecuté bien dentro de una ventana de consulta. No puedo duplicar el problema del violín tampoco. Una consulta como:
SELECT * FROM theFunction ('2013-04-01', '2013-06-01')
... también funciona bien.
¿Hay algo en la consulta (a continuación) que pueda causar que la función se bloquee cuando NULL
se pasa un para la fecha de finalización?
- Plan de ejecución para
SELECT * FROM theFunction ('2013-06-01', '2013-06-01')
- Plan estimado para
SELECT * FROM theFunction ('2013-06-01', NULL)
sql-server
sql-server-2008-r2
Kermit
fuente
fuente
CASE
conCOALESCE(@dateEnd,@dateStart)
, ¿sigue apareciendo el problema?ISNULL()
?SELECT task_state FROM sys.dm_os_tasks WHERE session_id = x
muestra? Si pasa mucho tiempo sin estar en elRUNNING
estado, ¿qué tipos de espera está recibiendo esa sesiónsys.dm_os_waiting_tasks
?COALESCE
.ISNULL
arreglado.Respuestas:
Parte de su consulta inicial es la siguiente.
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ónLa 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í.Y como hay un predicado de equi join,
b.[Date] = a.d
el plan también muestra un predicado de igualdadb.[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 comoque también se aplica como un predicado implícito en
ColleagueList
. El número estimado de filas esta vez es79.8
filas.La próxima unión es
colleagueTime
es una3,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. ElCOALESCE
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 deO en SQL
pero esto no cuadra con su comentario de que la columna no tiene
NULL
valores.fuente
NULL
valores para fechas en ninguna de esas tablas.dbo
no aparece en la lista. Solo otros esquemas que no uso.Parece que hubo un problema con los tipos de datos.
ISNULL
solucionado el problema (gracias ypercube ). Después de un poco de investigación,COALESCE
es el equivalente a laCASE
declaración que estaba usando:Paul White explica que:
Para evitar problemas de tipo de datos, parece que
ISNULL
es la función apropiada para tratar solo con dos expresiones.Extractos del plan XML
El plan XML que usa la
CASE
expresión 2 esNULL
:Plan XML utilizando
CASE
, la expresión 2 es una fecha:El plan XML que usa la
ISNULL
expresión 2 esNULL
:Plan XML utilizando
ISNULL
, la expresión 2 es una fecha:fuente
SELECT * FROM theFunction ('2013-06-01', '2013-06-01')
. La expresión datatype sigue siendo la misma. Y ambos parámetros son dedate
tipo de datos de todos modos. ¿Puedes ver los planes de ejecución?NULL
.CASE
también no tuvo efecto, la consulta aún se cuelga.ISNULL
miradas del plan como Simplifica mejor. Tiene un predicado de igualdad simple en ColleagueList de[Date]='2013-06-01'
mientras que elCASE
que tiene un predicado en[Date]>='2013-06-01' AND [Date]<=CASE WHEN (1) THEN '2013-06-01' ELSE NULL END AND PROBE([Bitmap1067],[Date])
. Las filas estimadas que salen de esa unión son 28,393 para laISNULL
versión, pero mucho más bajas79.8
para laCASE
versión que afecta la elección de la unión más adelante en el plan. No estoy seguro de por qué habría tanta discrepancia.