¿Por qué mi búsqueda de índice puede estimar el número correcto de filas y el operador de clasificación no puede?


11

Tengo una consulta que usa una función en el predicado, algo como esto:

commentType = 'EL'
AND commentDateTime >= DATEADD(month,datediff(month,0,getdate()) - 13,0)

Tengo un índice filtrado en commentType que tiene 40K filas y cuando ejecuto la consulta, el número estimado de filas para Index Seek es muy preciso (alrededor de 11K), pero para el siguiente paso (operador de clasificación) ignora por completo las estadísticas y solo estima el número total de filas en el índice filtrado.

¿Por qué está pasando esto? Sé lo básico sobre la sargabilidad , y lo probé solo por razones de cordura, reemplazando el dateadd por una fecha real (01-01-2014) y listo ... El tipo comenzó a adivinar el número de filas correctamente ...

¿Por qué sucede esto y cómo puedo solucionarlo? No puedo pasar una fecha fija ...


DATEADD(month,datediff(month,0,getdate()) - 13,0)no tiene sentido para mi ¿Qué intentas hacer con esto? ¿Se podría mejorar / simplificar?
Daniel Hutmacher

2
@Daniel Ese es el comienzo del mes, hace 13 meses.
Aaron Bertrand

1
Además, edite su pregunta para reflejar la versión de SQL Server (?) En la que se encuentra. Use etiquetas para eso.
Daniel Hutmacher

¿Podrías intentar DATEADD(month, -13, DATEADD(day, 1-DATEPART(day, SYSDATETIME()))ver si hay alguna diferencia?
Daniel Hutmacher

Si tiene un índice no filtrado (commentType, commentDate), ¿se comporta mejor allí? Es solo que los índices filtrados a veces pueden informar erróneamente las estimaciones en diferentes puntos de los planes. La estimación parece completa al informar el número total en el índice filtrado, pero en realidad es que el plan se muestra incorrectamente.
Rob Farley el

Respuestas:


9

Creo que sus estimaciones son incorrectas debido a un error del estimador que intercambia dos de los argumentos DATEDIFF. Hablo de esto aquí:

Una solución alternativa es calcular el primer día de hace 13 meses sin usar DATEDIFF (2008+):

DATEADD(MONTH, -13, DATEADD(DAY, 1-DATEPART(DAY,GETDATE()), CONVERT(DATE, GETDATE()));

No estoy seguro de que abordará la estimación (no he probado con índices filtrados, y no estoy seguro de qué está haciendo realmente el tipo o por qué tiene una estimación diferente sin el plan y / o el resto de la consulta )

La solución que Microsoft recomienda es usar TF 4199, pero no estoy tan seguro de que sea lo que deba hacer aquí:

Otra opción sería asegurarse de estar en el último SP / CU absoluto para cualquier versión de SQL Server que esté utilizando, ya que afirman que está solucionado en el siguiente artículo de KB (aunque esto aún requerirá el uso de TF 4199 a menos que esté en 2014 o mejor):

La solución se puede obtener con las siguientes compilaciones:

(La próxima vez, incluya los resultados de SELECT @@VERSIONen su pregunta).

Notaré que el artículo de KB dice que DATEDIFF puede subestimar el número de filas, que es lo contrario de lo que está sucediendo en su escenario. Eso no significa que las correcciones no se apliquen a usted; Creo que la redacción del artículo de KB es inexacta, ya que las estimaciones pueden ir en cualquier dirección dependiendo de los datos y el rango que esté viendo.

Mi publicación de blog anterior confirmó que el intercambio ya no se produce en 2014 o más. Para estar seguro, probablemente simplemente eliminaría DATEDIFF de su predicado y usaría un método diferente para calcular el comienzo de su rango. No sugiero la exageración de 4199 o el uso de SQL dinámico para evitar el intercambio incorrecto.


Gracias por la ayuda ! Intenté su sugerencia y el plan cambió. Así era antes: s16.postimg.org/t5j6o1yed/fix_wrong.png Así es después de que cambié mi fecha por la tuya: postimg.org/image/5f725rj83 Voy a leer todas las URL que me diste . Salud.
MrKudz
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.