Una vez a la semana, durante las últimas 5 semanas, aproximadamente a la misma hora del día (temprano en la mañana, puede basarse en la actividad del usuario cuando las personas comienzan a usarlo), SQL Server 2016 (AWS RDS, duplicado) comienza a agotar el tiempo de espera. consultas
ACTUALIZAR ESTADÍSTICAS en todas las tablas siempre lo corrige de inmediato.
Después de la primera vez, hice que actualizara todas las estadísticas en todas las mesas todas las noches (en lugar de semanalmente), pero aún así sucedió (aproximadamente 8 horas después de que se ejecuta la actualización de estadísticas, pero no todos los días que se ejecuta).
Esta última vez, habilité Query Store para ver si podía encontrar qué consulta / plan de consulta específico era. Creo que pude reducirlo a uno:
Después de encontrar esa consulta, agregué un índice recomendado que faltaba en esta consulta no utilizada con frecuencia (pero que toca muchas tablas de uso frecuente).
El plan de consulta incorrecto estaba haciendo una exploración de índice (en una tabla con solo 10k filas). Sin embargo, otros planes de consulta que regresaron en milisegundos solían hacer el mismo análisis. El plan de consulta más reciente, después de crear el nuevo índice, solo busca. Pero incluso sin ese índice, el 99% del tiempo, regresaba en unos pocos milisegundos, pero luego, semanalmente, tomaría> 40 segundos.
- Malo que agota el tiempo de espera: http://brentozar.com/pastetheplan/?id=rymaWt56e
- Planes anteriores que no caducan : http://brentozar.com/pastetheplan/?id=HyN7ftcpe
- Plan más nuevo con nuevo índice: http://brentozar.com/pastetheplan/?id=ryLuGKcag
Esto comenzó a suceder después de pasar a SQL Server 2016 desde 2012.
DBCC CHECKDB no devuelve errores.
- ¿El nuevo índice solucionará el problema, haciendo que nunca vuelva a elegir el mal plan?
- ¿Debo "forzar" el plan que funciona bien ahora?
- ¿Cómo me aseguro de que esto no le suceda a otra consulta / plan?
- ¿Es este un síntoma de un problema mayor?
Índices que acabo de agregar:
CREATE NONCLUSTERED INDEX idx_AppointmetnAttendee_AttendeeType
ON [dbo].[AppointmentAttendee] ([UserID],[AttendeeType])
CREATE NONCLUSTERED INDEX [idx_appointment_start] ON [dbo].[Appointment]
(
[ProjectID] ASC,
[Start] ASC
)
INCLUDE ( [ID],
[AllDay],
[End],
[Location],
[Notes],
[Title],
[CreatedByID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
Texto completo de la consulta:
https://pastebin.com/Z5szPBfu (generado por LINQ, puedo / debería poder optimizar las columnas seleccionadas, pero debería ser irrelevante para este problema)
fuente
Respuestas:
Voy a responder sus preguntas en un orden diferente al que usted me hizo.
El nuevo estimador de cardinalidad en SQL Server 2016 podría estar contribuyendo al problema. SQL Server 2012 usa el CE heredado y no experimentó su problema en esa versión. El nuevo estimador de cardinalidad hace diferentes suposiciones sobre sus datos y puede generar diferentes planes de consulta para el mismo SQL. Puede experimentar un mejor rendimiento para algunas consultas con el CE heredado dependiendo de su consulta y sus datos. Por lo tanto, algunas partes de su modelo de datos pueden no ser la mejor combinación para el nuevo CE. Eso está bien, pero es posible que deba evitar el nuevo CE por ahora.
También me preocuparía el rendimiento inconsistente de las consultas incluso con las actualizaciones diarias de estadísticas. Una cosa importante a tener en cuenta es que la recopilación de estadísticas en todas las tablas eliminará efectivamente todos los planes de consulta de la memoria caché, por lo que podría tener un problema con las estadísticas o podría tener que ver con la detección de parámetros. Es difícil tomar una determinación sin mucha información sobre su modelo de datos, tasa de cambio de datos, políticas de actualización de estadísticas, cómo está llamando a su código, etc. SQL Server 2016 ofrece algunas configuraciones de nivel de base de datos para la detección de parámetros que podrían ser útiles. , pero eso podría afectar toda su aplicación en lugar de solo una consulta problemática.
Lanzaré un escenario de ejemplo que podría conducir a este comportamiento. Tu dijiste:
Suponga que reúne estadísticas en todas las tablas que borran todos los planes de consulta. Dependiendo de los factores mencionados anteriormente, si la primera consulta del día es contra un usuario con solo 1 registro de permiso, SQL Server puede almacenar en caché un plan que funciona bien para usuarios con 1 registro, pero funciona terriblemente con usuarios con 20k registros. Si la primera consulta del día es contra un usuario con 20k registros, entonces puede obtener un buen plan para 20k registros. Cuando el código se ejecuta contra un usuario con 1 registro, puede que no sea la consulta más óptima, pero aún puede terminar en ms. Realmente suena como rastreo de parámetros. Explica por qué no siempre ves el problema o por qué a veces lleva horas aparecer.
Creo que uno de los índices que agregó evitará el problema porque acceder a los datos requeridos a través del índice será más barato que realizar un análisis de índice agrupado en la tabla, especialmente cuando el análisis no puede finalizar antes de tiempo. Vamos a acercarnos a la parte mala del plan de consulta:
SQL Server estima que solo se devolverá una fila de la unión en
[Permission]
y[Project]
. Para cada fila en la entrada externa, se realizará una exploración de índice agrupado[Appointment]
. Todas las filas se escanearán desde esta tabla, pero solo aquellas que coincidan con el filtrado[Start]
se devolverán al operador de unión. Dentro del operador de unión, los resultados se reducen aún más.El plan de consulta descrito anteriormente puede estar bien si realmente solo se envía una fila a la entrada externa de la unión. Sin embargo, si la estimación de cardinalidad de la unión es incorrecta y obtenemos, digamos, 1000 filas, entonces SQL Server realizará 1000 escaneos de índice agrupados
[Appointment]
. El rendimiento del plan de consulta es muy sensible a los problemas de estimación.La forma más directa de nunca volver a obtener ese plan de consulta sería crear un índice de cobertura contra la
[Appointment]
tabla. Algo así como un índice[ProjectId]
y[Start]
debería hacerlo. Parece que este es exactamente el[idx_appointment_start]
índice que creó para abordar el problema. Otra forma de disuadir al servidor SQL de elegir el plan de consulta es arreglar la estimación de cardinalidad de la unión en[Permission]
y[Project]
. Las formas típicas de hacerlo incluyen cambiar el código, actualizar estadísticas, usar el CE heredado, crear estadísticas de varias columnas, dar a SQL Server más información sobre variables locales, como unaRECOMPILE
pista, o materializar esas filas en una tabla temporal. Muchas de esas técnicas no son un buen enfoque cuando necesita un tiempo de respuesta de nivel ms o tiene que escribir código a través de un ORM.El índice que creó en
[AppointmentAttendee]
no es una forma directa de abordar el problema. Sin embargo, obtendrá estadísticas de varias columnas en el índice y esas estadísticas podrían desalentar el plan de consulta incorrecto. El índice puede proporcionar una forma más eficiente de acceder a los datos, lo que también puede desalentar el mal plan de consulta, pero no creo que haya ningún tipo de garantía de que no vuelva a suceder solo con el índice activado[AppointmentAttendee]
.Entiendo por qué haces esta pregunta, pero es extremadamente amplia. Mi único consejo es tratar de comprender mejor la causa raíz de la inestabilidad del plan de consulta, validar que tiene los índices correctos creados para su carga de trabajo y probar y monitorear cuidadosamente su carga de trabajo. Microsoft tiene algunos consejos generales sobre cómo lidiar con las regresiones del plan de consultas causadas por el nuevo CE en SQL Server 2016:
No estoy diciendo que deba bajar a SQL Server 2012 y comenzar de nuevo, pero la técnica general descrita puede ser útil para usted.
Depende completamente de usted. Si cree que tiene un plan de consulta que funciona bien para todos los parámetros de entrada posibles, se siente cómodo con la funcionalidad del almacén de consultas y desea la tranquilidad que conlleva forzar un plan de consulta, entonces hágalo. Forzar planes de consulta que tuvieron regresiones es parte de la política de actualización recomendada por Microsoft a SQL Server 2016 después de todo.
fuente